Details
-
Bug
-
Resolution: Unresolved
-
P1: Critical
-
5.6, 5.15.11, 6.2.4, 6.3.2, 6.4.1
-
Windows 11, Ubuntu 22.04
-
e3f593da8 (dev), a0dba498b (6.7)
Description
tl;dr: PropertyChanges doesn't really work with signal handlers because there can be multiple signal handlers attached to the same signal and PropertyChanges doesn't know which one to replace. There should be a signal-specific state operation that allows you to specify what to replace.
If multiple properties are declared in a C++ component using the Q_PROPERTY macro and share the same notification signal, a QML PropertyChanges element can only add/replace the handler for one of properties. When multiple signal handlers are set via a PropertyChanges element, only the first declared signal handler works.
I should be able to use a PropertyChanges element to add a "property changed" signal handler for each property declared using a shared notification signal, but this does not work. If each property has its own notification signal, there is no problem.
Below is an example of what I mean by "shared notification signals":
// code placeholder class Monitor: public QObject { Q_OBJECT // each property has the same notification signal Q_PROPERTY(int value1 READ value1 NOTIFY readCompleted) Q_PROPERTY(int value2 READ value2 NOTIFY readCompleted) Q_PROPERTY(int value3 READ value3 NOTIFY readCompleted) public: explicit Monitor(QObject *parent = nullptr) : QObject(parent) {} signals: void readCompleted(); public slots: void readSensor() { for (auto& v : mValues) v += 3; emit readCompleted(); } private: // value1, value2, and value3 are stored in an array which is updated by calling readSensor() int value1() const { return mValues[0]; } int value2() const { return mValues[1]; } int value3() const { return mValues[2]; } int mValues[3] { 1, 2, 3 }; };
Below is an example of a QML declaration where I expect to be able to replace all signal handlers:
Item { Monitor { id: monitor // original handlers show red text onValue1Changed: window.log("red", "onValue1Changed", value1) onValue2Changed: window.log("red", "onValue2Changed", value2) onValue3Changed: window.log("red", "onValue3Changed", value3) } states: State { name: "modifiedBehavior" when: true PropertyChanges { target: monitor // if handlers are replaced using PropertyChanges, text is blue onValue1Changed: window.log("blue", "PropertyChanges value1", value1) onValue2Changed: window.log("blue", "PropertyChanges value2", value2) onValue3Changed: window.log("blue", "PropertyChanges value3", value3) } } }
Below is the output when the properties change. The red output is from property change handlers declared within the component in QML and indicates that the original signal handlers are not replaced by the PropertyChanges element.:
Using a Connections QML element (not demonstrated) proves that individual property change signals are emitted correctly for each property even though the same notification signal is declared in C++.
If each property has its own notification signal instead of sharing the signals, I can replace all the signal handlers. This is the behavior I expected but did not see with shared notification signals for the properties. You can see this behavior by changing the #if 0 directive in the attached project: