diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 6fe32e842ad..8f95b5fd5e3 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -1344,6 +1344,10 @@ QString QPropertyBindingError::description() const \snippet code/src_corelib_kernel_qproperty.cpp 2 + The change handler can optionally accept one argument, of the same type as the property, + in which case it is passed the new value of the property. Otherwise, it should take no + arguments. + If the property does not need a changed notification, you can leave out the "NOTIFY xChanged" in the Q_PROPERTY macro as well as the last argument of the Q_OBJECT_BINDABLE_PROPERTY and Q_OBJECT_BINDABLE_PROPERTY_WITH_ARGS diff --git a/src/corelib/kernel/qproperty.h b/src/corelib/kernel/qproperty.h index 6cf8c6a34e0..108f041d4fc 100644 --- a/src/corelib/kernel/qproperty.h +++ b/src/corelib/kernel/qproperty.h @@ -884,6 +884,7 @@ class QObjectBindableProperty : public QPropertyData { using ThisType = QObjectBindableProperty; static bool constexpr HasSignal = !std::is_same_v; + using SignalTakesValue = std::is_invocable; Class *owner() { char *that = reinterpret_cast(this); @@ -897,8 +898,12 @@ class QObjectBindableProperty : public QPropertyData static void signalCallBack(QUntypedPropertyData *o) { QObjectBindableProperty *that = static_cast(o); - if constexpr (HasSignal) - (that->owner()->*Signal)(); + if constexpr (HasSignal) { + if constexpr (SignalTakesValue::value) + (that->owner()->*Signal)(that->valueBypassingBindings()); + else + (that->owner()->*Signal)(); + } } public: using value_type = typename QPropertyData::value_type; @@ -1060,8 +1065,12 @@ private: { if (binding) binding->notifyObservers(this); - if constexpr (HasSignal) - (owner()->*Signal)(); + if constexpr (HasSignal) { + if constexpr (SignalTakesValue::value) + (owner()->*Signal)(this->valueBypassingBindings()); + else + (owner()->*Signal)(); + } } }; diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 5197be3912e..6d28fd6747d 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -83,6 +83,7 @@ private slots: void quntypedBindableApi(); void readonlyConstQBindable(); void qobjectBindableManualNotify(); + void qobjectBindableSignalTakingNewValue(); void testNewStuff(); void qobjectObservers(); @@ -1088,7 +1089,7 @@ class MyQObject : public QObject Q_PROPERTY(int compat READ compat WRITE setCompat NOTIFY compatChanged) signals: - void fooChanged(); + void fooChanged(int newFoo); void barChanged(); void compatChanged(); @@ -1182,6 +1183,28 @@ void tst_QProperty::qobjectBindableManualNotify() QCOMPARE(object.foo(), 1); } +void tst_QProperty::qobjectBindableSignalTakingNewValue() +{ + // Given an object of type MyQObject, + MyQObject object; + // and tracking the values emitted via its fooChanged signal, + int newValue = -1; + QObject::connect(&object, &MyQObject::fooChanged, [&](int i){ newValue = i; } ); + + // when we change the property's value via the bindable interface + object.bindableFoo().setValue(1); + // we obtain the newly set value. + QCOMPARE(newValue, 1); + + // The same holds true when we set a binding + QProperty i {2}; + object.bindableFoo().setBinding(Qt::makePropertyBinding(i)); + QCOMPARE(newValue, 2); + // and when the binding gets reevaluated to a new value + i = 3; + QCOMPARE(newValue, 3); +} + void tst_QProperty::testNewStuff() { MyQObject testReadOnly;