PDA

View Full Version : when QBuffer emits readyRead signal?



mastupristi
4th April 2016, 16:26
Hi

Reading QBuffer documentation:

QBuffer emits readyRead() (http://doc.qt.io/qt-5/qiodevice.html#readyRead) when new data has arrived in the buffer.

The question is: how new data can arrive in the buffer?
I mean, I declared a QBuffer:


QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::ReadWrite);

In my thought new data is considered arrived if I write data in the byteArray directly:

byteArray.append("hallo");
but readyRead() is never called

so how new data can arrive in the buffer to make readyRead() be emitted?

best reagards
Max

d_stranz
4th April 2016, 17:59
I think you misunderstand how the QBuffer / QByteArray relationship works. As the docs say:


The QBuffer class provides a QIODevice interface for a QByteArray.
...
QBuffer allows you to access a QByteArray using the QIODevice interface. The QByteArray is treated just as a standard random-accessed file. \
By default, an internal QByteArray buffer is created for you when you create a QBuffer. You can access this buffer directly by calling buffer(). You can also use QBuffer with an existing QByteArray by calling setBuffer(), or by passing your array to QBuffer's constructor.

You read and write from the QBuffer instance, not the QByteArray. The QByteArray is just the internal storage used by the QBuffer. QBuffer allows you to treat a QByteArray as if it was a file or other random access I/O device.

So when you write to the QBuffer instance, that is when the readyRead signal is emitted. Your slot can then retrieve the QByteArray and read the new contents.

mastupristi
4th April 2016, 20:23
So when you write to the QBuffer instance, that is when the readyRead signal is emitted. Your slot can then retrieve the QByteArray and read the new contents.

I tried a little example
11851


class Dialog : public QDialog
{
Q_OBJECT

public:
explicit Dialog(QWidget *parent = 0);
~Dialog();

private:
Ui::Dialog *ui;

QBuffer *m_buffer;
QByteArray *m_bytearray;

public slots:
void onClick(void);
void onDataReady(void);
};


Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);

m_bytearray = new QByteArray;
m_buffer = new QBuffer(m_bytearray);
m_buffer->open(QIODevice::ReadWrite);

connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(onClick()));
connect(m_buffer, SIGNAL(readyRead()), this, SLOT(onDataReady()));
}

Dialog::~Dialog()
{
delete m_buffer;
delete m_bytearray;
delete ui;
}

void Dialog::onClick(void)
{
qDebug() << "write in buffer";
m_buffer->write("hallo");
}

void Dialog::onDataReady(void)
{
QByteArray ba;
ba = m_buffer->readAll();
qDebug() << "read" << ba.size() << "bytes";
}


when write() is called the readyRead() actually emitted.
But once in the onDataReady(), the call to readAll() returns an empty bytearray, though in m_bytearray is present the string "hallo".

It seems that it is positioned to the end of the bytearray. I tried to modify:

void Dialog::onClick(void)
{
qDebug() << "write in buffer";
m_buffer->write("hallo");
m_buffer->reset();
}

This works, but the second time I click the button it read a string "hallohallo", the third I read "hallohallohallo", an so on...

what is the proper way to read only bytes written in onClick()?

best regards
max

d_stranz
5th April 2016, 06:26
You still misunderstand, I think.

When you construct a QBuffer with a QByteArray as an argument, that QByteArray is the one that will be modified when you call QBuffer::write(). Calling QBuffer::readAll() returns the internal QByteArray, not the one you gave it as the constructor argument. So of course, the internal array is empty because you told QBuffer not to use it, but to use yours instead.

So the code you wrote first will work if you simply replace this line:


m_buffer = new QBuffer(m_bytearray);

with this line:


m_buffer = new QBuffer();

When you call QBuffer::reset(), you are telling QBuffer to go back to using its internal buffer and ignore yours, which is why you get a copy of your string in that case. Each time you write, you append more data to the buffer (which is why you get multiple copies of the string).

anda_skoa
5th April 2016, 10:33
Since you have two access points I guess you will have to maintain your two positions yourself.

Compare that with QFile, which is also a QIODevice.
If you append to it, then the position information (QIODevice::pos() is the end of the file. If you start a read there, you won't get any data (you are at the end of the file after all).

So you need to remember your read and write positions, then seek to the correct one before you perform the I/O operation.

Cheers,
_

d_stranz
5th April 2016, 22:09
It sounds like you want the buffer to contain only the most recently written bytes. I think in this case you need to do something like the following:



QByteArray copy = mpBuffer->readAll();
QByteArray & internal = mpBuffer->buffer();
internal.clear();
mpBuffer->seek( 0 ); // Maybe not required; QBuffer might check the array size before writing


This should result in an empty buffer without a readyRead() signal. As the docs say:



QByteArray & QBuffer::buffer()

Returns a reference to the QBuffer's internal buffer. You can use it to modify the QByteArray behind the QBuffer's back.