Solved QDatastream deserialze Q_PROPERTY signal change
-
Hello, I'm receiving data by ethernet (TCP) and I would like to parse the datastream into my dataclass which shall be populated to qml. I would like to get notified, after a change of the value.
class student : public QObject { Q_OBJECT // Q_OBJECT macro will take care of generating proper metaObject for your class Q_PROPERTY(int id READ getId WRITE setId) Q_PROPERTY(QString Name READ getName WRITE setName) public: student(); int getId() const { return id; } void setId(int newId) { id = newId; } QString getName() const { return Name; } void setName(const QString &newName) { Name = newName; } private: int id; QString Name; };
If I deserialze my QByteArray by QDatastream into the private member, then I don't get the notification, because I don't use my setter.
// no notification about propertychange QByteArray ba; // mydata inside QDataStream in (&ba,QIODevice::ReadWrite) in << m_id << m_name;
This seems not to be allowed:
QByteArray ba; // mydata inside QDataStream in (&ba,QIODevice::ReadWrite) in << set_Id(m_id) << set_Name (m_name); // not allowed?!
Question:
- How I can get my notification about the change?
- Do you recommend different approche to deserialze to my dataclass?
-
@shazter Hi,
To get notification, you need to specify and define signals for properties changes.
class student : public QObject { Q_OBJECT Q_PROPERTY(int id READ getId WRITE setId NOTIFY idChanged) Q_PROPERTY(QString Name READ getName WRITE setName NOTIFY nameChanged) ... signals: void idChanged(int id); void nameChanged(const QString &name); ... };
Then you need to update your setters to call the signal when a modification occurs:
void setId(int newId) { if(id == newId) return; id = newId; emit idChanged(newId); } void setName(const QString &newName) { if(Name == newName) return; Name = newName; emit nameChanged(newName); }
Note you can also remove the actual setters and generate them automatically from Qt Creator. In my case I'm using ALT + RETURN shortcut (Windows) on the line where Q_PROPERTY is defined and it shows a menu "add missing members" which generates member variable, getter, setter and signal of the property.
About deserializing, I think it should be something like:
// no notification about propertychange QByteArray ba; // mydata inside QDataStream in (&ba) QString id; QString name; in >> id >> name; setId(id); setName(name);
-
@shazter Just another remarks about naming conventions. I suggest that you use Uppercase first for naming your classes, and also using m_or m prefix for your member variables to avoid confusions.
In the classstudent
, there is one property nameid
which starts with lowercase character, and the other oneName
with uppercase character. I think this is very confusing.For exemple, I would rename class
student
toStudent
,id
tom_id
andName
tom_name
That's not really critical but when you have tens of classes or variables it makes everything more clear.
-
Many thanks for your example and advice this helps me alot.
Oh sorry forgot to add the signals and of course the my Q_PROPERTY example was wrong.
QString id; QString name; in >> id >> name; setId(id); setName(name);
I hoped to avoid so much boiler code and additional temporary variables, because one message frame can be maxsize ~64kByte, but looks like their is no better solution to get the notification update.
-
I forgot to ask one more question to the same topic.
When I updated my private members by Q_PROPERTY setter in QML the UI will show the values immanently , then members will serialized to QDatastream, and then send to tcp-client. The client shall confirm data was a received and CRC check was successful too, means no problem with shown values in UI both are consistent. If the received data is for some reason partly corrupted, then client will send again frame with current valid data, then I started the deserialze again and settings the dataclass again to show the correct values.
Is this understanding correct?
Or shall I show all old values until the client has confirmed received data and then emit a signal for each member value by using the setter?
-
@shazter The way you manage errors are IMHO depending of the context of the application and how you want it to behave. I don't think a method is better than another.