Сигнал изменения свойства указателя QML не распространяется на свойства привязки

Я представил переменную указателя для qml следующим образом:

Фрукты:

class Fruit : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int qualityGrade READ qualityGrade WRITE setQualityGrade NOTIFY qualityGradeChanged)
    Q_PROPERTY(bool organic READ organic WRITE setOrganic NOTIFY organicChanged)
public:
    int qualityGrade() const
    {
        return m_qualityGrade;
    }

    bool organic() const
    {
        return m_organic;
    }

public slots:
    void setQualityGrade(int qualityGrade)
    {
        if (m_qualityGrade == qualityGrade)
            return;

        m_qualityGrade = qualityGrade;
        emit qualityGradeChanged(m_qualityGrade);
    }

    void setOrganic(bool organic)
    {
        if (m_organic == organic)
            return;

        m_organic = organic;
        emit organicChanged(m_organic);
    }

signals:
    void qualityGradeChanged(int qualityGrade);

    void organicChanged(bool organic);

private:
    int m_qualityGrade = -1;
    bool m_organic = false;
};

МойКласс.h:

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Fruit* featuredFruit READ featuredFruit WRITE setFeaturedFruit NOTIFY featuredFruitChanged)
public:
    explicit MyClass(QObject *parent = nullptr);
    ~MyClass();

    Fruit* featuredFruit() const
    {
        return m_featuredFruit;
    }

public slots:
    void setFeaturedFruit(Fruit* featuredFruit)
    {
        if (m_featuredFruit == featuredFruit)
            return;

        m_featuredFruit = featuredFruit;
        emit featuredFruitChanged(m_featuredFruit);
    }

signals:
    void featuredFruitChanged(Fruit* featuredFruit);

private:

    Fruit* m_featuredFruit = nullptr;
};

MyClass.cpp:

MyClass::MyClass(QObject *parent) : QObject(parent)
{
    m_featuredFruit = new Fruit();
    m_featuredFruit->setQualityGrade(2);

    QTimer *timer = new QTimer();
    connect(timer, &QTimer::timeout, this, [=]() {
        //m_featuredFruit->deleteLater();           //<--- activating these two lines causes to force working featuredFruitChanged signal
        //m_featuredFruit = new Fruit();
        m_featuredFruit->setQualityGrade(5);
        emit featuredFruitChanged(m_featuredFruit);
        delete timer;
    });
    timer->start(5000);
}

MyClass::~MyClass()
{
    m_featuredFruit->deleteLater();
    m_featuredFruit = nullptr;
}

и я использовал его в QML следующим образом:

MyClass {
    id: classObj
    onFeaturedFruitChanged: console.log("original property shows an change");//<--- called as expected
}

Item {
    property Fruit selectedFruit: classObj.featuredFruit //<--- binding qml defined property to C++ property
    
    onSelectedFruitChanged: {
        console.log("binded property recieved change signal");//<--- not called after changes!!!
        alertAnimation.restart();   //<--- an example of usage
    }
}

Проблема в том, что всякий раз, когда я испускаю featuredFruitChanged, свойство связывания qml не получает сигнал об изменении.
Что не так?! Это ошибка Qt Framework? Есть предложения?

Также я безуспешно пытался перегрузить оператор равенства в С++.

Обновлять:

Хорошо, я добавляю некоторые уточнения к моему примеру кода, чтобы легче воспроизвести проблему.
Исправлена ​​опечатка в моем примере кода (спасибо @ihor-drachuk). Проблема пока есть.


person S.M.Mousavi    schedule 26.07.2020    source источник
comment
Как вы ожидаете, что это должно работать? Насколько я знаю, свойства on*Changed для объектов работают на назначение/переназначение, но не на изменение внутреннего состояния. Вы должны привязать обработчик к указанному свойству, чтобы получать уведомления при его изменении, а не ко всему объекту.   -  person folibis    schedule 26.07.2020
comment
@фолибис Нет! on*Changed работает только тогда, когда связанный сигнал испускается, а не когда вы присваиваете значение (как описано в Qt Doc). Fruit также является свойством, поэтому его сигнал об изменении должен уведомлять qml об изменении. Это работает, как и ожидалось. Но проблема в том, что сигнал изменения не распространяется на второе свойство qml (которое связано с первым свойством). [C++: выдать изменение]=====›[QML: хорошо, изменено]=====›[второе свойство QML: ничего не происходит! :| ]   -  person S.M.Mousavi    schedule 26.07.2020


Ответы (1)


Потому что вы написали с ошибкой featuredFruit и написали featuedFruit. Исправьте это, и это будет работать.

Обновление: должно работать, если вызвать setFeaturedFruit или изменить его из QML. Это не будет работать, как вы ожидаете, если изменить какое-либо свойство featuredFruit, даже если оно выбрано

Обновление 2: QML вызывает onChanged, если значение изменено, значение является указателем на объект. Итак, если указатель изменился, будет вызван onChanged. Если что-то за указателем изменилось - нет.

Но вы можете справиться с этим с помощью Connections:

Connections {
    target: classObj.featuredFruit

    onTargetChanged: console.warn("Target changed!");
    onQualityGradeChanged: console.warn("onQualityGradeChanged!");
    onOrganicChanged: console.warn("onOrganicChanged!");
}

Также вы можете добавить к Fruit какой-то специальный сигнал, например somethingChangedInMe, и генерировать его в каждом сеттере. Итак, вы можете написать в Connections вот такой обработчик сигнала:

Connections {
    target: classObj.featuredFruit

    onTargetChanged: console.warn("Target changed!");
    onSomethingChangedInMe: console.warn("onSomethingChangedInMe!");
}
person Ihor Drachuk    schedule 26.07.2020
comment
ой! извините, это всего лишь пример кода, и я исправил свой вопрос. Также я проверил именование в реальном проекте, и никаких проблем не было обнаружено. на самом деле, если я проверяю значение selectedFruit в обработчике onFeaturedFruitChanged, данные обновляются, но сигнал не передается в свойство qml с именем selectedFruit. (так как это указатель) - person S.M.Mousavi; 26.07.2020
comment
Хм, странно... на самом деле, я пробовал, и если исправить опечатку - все действительно работало как надо, все сигналы и обработчики вызывались. Но я не вижу полного исходника, возможно я неправильно воспроизвел проблему. Это должно работать, если вызвать setFeaturedFruit или изменить его из QML. Это не будет работать, как вы ожидаете, если изменить какое-либо свойство featuredFruit - person Ihor Drachuk; 27.07.2020
comment
Я обновил вопрос и исправил опечатку. Как правило, изменение значения свойства с помощью сигнала изменения будет работать. Но в этом случае связанное имущество не уведомляется об изменении. - person S.M.Mousavi; 27.07.2020
comment
Наверное, потому что на самом деле он не изменился. Вы испускаете одно и то же значение - person Ihor Drachuk; 27.07.2020
comment
Вот пример с вашим источником, он отлично работает: file.io/Jw7O2XASCzl3, он также отлично работает на вашем ПК? - person Ihor Drachuk; 27.07.2020
comment
ссылка повреждена (ошибка 404). Я думаю, что внутреннее поведение Qt таково, что предотвращает испускание изменений для одного и того же объекта. даже если внутренняя часть этого объекта полностью изменена:/ Поэтому я попытался перегрузить operator==(), чтобы контролировать это поведение, но безуспешно:/ - person S.M.Mousavi; 27.07.2020
comment
Давайте продолжим обсуждение в чате. - person Ihor Drachuk; 27.07.2020
comment
Я отредактировал ответ. Также я загрузил исходники на другой ресурс, надеюсь их можно будет скачать fex.net/s/sske7xz - person Ihor Drachuk; 27.07.2020