diff --git a/src/corelib/kernel/qproperty.cpp b/src/corelib/kernel/qproperty.cpp index 3a2c8dcc0ce..14ee881455b 100644 --- a/src/corelib/kernel/qproperty.cpp +++ b/src/corelib/kernel/qproperty.cpp @@ -239,8 +239,11 @@ QUntypedPropertyBinding QPropertyBindingData::setBinding(const QUntypedPropertyB if (observer) newBinding->prependObserver(observer); newBinding->setStaticObserver(staticObserverCallback, guardCallback); - if (newBinding->requiresEagerEvaluation()) - newBinding->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr); + if (newBinding->requiresEagerEvaluation()) { + auto changed = newBinding->evaluateIfDirtyAndReturnTrueIfValueChanged(propertyDataPtr); + if (changed) + observer.notify(newBinding.data(), propertyDataPtr, /*alreadyKnownToHaveChanged=*/true); + } } else if (observer) { d.setObservers(observer.ptr); } else { @@ -435,9 +438,18 @@ void QPropertyObserverPointer::setBindingToMarkDirty(QPropertyBindingPrivate *bi ptr->next.setTag(QPropertyObserver::ObserverNotifiesBinding); } -void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding, QUntypedPropertyData *propertyDataPtr) +/*! \internal + \a propertyDataPtr is a pointer to the observed property's property data + In case that property has a binding, \a triggeringBinding points to the binding's QPropertyBindingPrivate + \a alreadyKnownToHaveChanged is an optional parameter, which is needed in the case + of eager evaluation: + There, we have already evaluated the binding, and thus the change detection for the + ObserverNotifiesChangeHandler case would not work. Thus we instead pass the knowledge of + whether the value has changed we obtained when evaluating the binding eagerly along + */ +void QPropertyObserverPointer::notify(QPropertyBindingPrivate *triggeringBinding, QUntypedPropertyData *propertyDataPtr,bool alreadyKnownToHaveChanged) { - bool knownIfPropertyChanged = false; + bool knownIfPropertyChanged = alreadyKnownToHaveChanged; bool propertyChanged = true; auto observer = const_cast(ptr); diff --git a/src/corelib/kernel/qproperty_p.h b/src/corelib/kernel/qproperty_p.h index 1bf308e8ea1..aa81aa92034 100644 --- a/src/corelib/kernel/qproperty_p.h +++ b/src/corelib/kernel/qproperty_p.h @@ -106,7 +106,7 @@ struct QPropertyObserverPointer void setChangeHandler(QPropertyObserver::ChangeHandler changeHandler); void setAliasedProperty(QUntypedPropertyData *propertyPtr); - void notify(QPropertyBindingPrivate *triggeringBinding, QUntypedPropertyData *propertyDataPtr); + void notify(QPropertyBindingPrivate *triggeringBinding, QUntypedPropertyData *propertyDataPtr, const bool alreadyKnownToHaveChanged = false); void observeProperty(QPropertyBindingDataPointer property); explicit operator bool() const { return ptr != nullptr; } @@ -409,10 +409,7 @@ public: { QtPrivate::QPropertyBindingData *bd = qGetBindingStorage(owner())->bindingData(this, true); QUntypedPropertyBinding oldBinding(bd->setBinding(newBinding, this, nullptr, bindingWrapper)); - // refetch the binding data, as the eager evaluation in setBinding() above could cause a reallocation - // in the binding storage - bd = qGetBindingStorage(owner())->bindingData(this); - notify(bd); + // notification is already handled in QPropertyBindingData::setBinding return static_cast &>(oldBinding); } diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp index 565916b781d..344ced91011 100644 --- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp +++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp @@ -432,7 +432,7 @@ class BindingLoopTester : public QObject public: BindingLoopTester(QProperty *i, QObject *parent = nullptr) : QObject(parent) { eagerData.setBinding(Qt::makePropertyBinding([&](){ return eagerData2.value() + i->value(); } ) ); - eagerData2.setBinding(Qt::makePropertyBinding([&](){ return eagerData.value(); } ) ); + eagerData2.setBinding(Qt::makePropertyBinding([&](){ return eagerData.value() + 1; } ) ); i->setValue(42); } @@ -532,7 +532,6 @@ void tst_QProperty::realloc() tester.bindableProp3().setBinding([&](){return tester.prop5();}); tester.bindableProp4().setBinding([&](){return tester.prop5();}); tester.bindableProp5().setBinding([&]() -> int{return 42;}); - QEXPECT_FAIL("", "ChangeHandler bug with eager properties", Continue); QCOMPARE(modificationCount, 2); } };