【问题标题】:How to re-evaluate c++ function bound to qml property on dependent property change?如何在依赖属性更改时重新评估绑定到 qml 属性的 c++ 函数?
【发布时间】:2014-10-13 04:35:56
【问题描述】:

我想将 C++ 类的方法绑定到 QML 组件属性,并在依赖属性更改时重新评估它。以下 QML 组件可以满足我的要求:

// Converter.qml:
import QtQuick 2.0

QtObject {
    property double rate: 1
    function exchange(amount) { return amount * rate }
}

如果我将exchange 函数的结果分配给这样的属性,

Text { text: converter.exchange(100) }

rate 更改时,Text 元素将自动更新。这适用于 QML 组件,但我不知道如何使用 C++ 类。

我想在 C++ 中实现一个功能等效的类:

#include <QObject>

class Convert : public QObject
{
    Q_OBJECT
    Q_PROPERTY(double rate READ rate WRITE setRate NOTIFY rateChanged)

public:
    explicit Convert(QObject *parent = 0)
        : QObject(parent), m_rate(1.0)
    { }

signals:
    void rateChanged();

public slots:
    double exchange(double amount) { return m_rate * amount; }

    double rate() { return m_rate; }

    void setRate(double r) {
        m_rate = r;
        emit rateChanged();
    }

private:
    double m_rate;
};

rate 属性可从 QML 访问,但更改它不会向 QML 引擎发出信号,即应重新评估“交换”。

这是我的 main.qml:

// main.qml
import QtQuick 2.1
import QtQuick.Controls 1.1
import Utils 1.0

ApplicationWindow {
    width: 300; height: 200
    visible: true

//    Converter { id: converter; rate: rateField.text }
    CppConverter { id: converter; rate: rateField.text }
    Column {
        TextField { id: rateInput; text: '0.41' }
        TextField { id: amountInput; text: '100.00' }
        Text { id: output; text: converter.exchange(amountField.text).toFixed(2) }
    }
}

如果我启用CppConverter,当我更改amountInput 时输出会更新,不会在我更改rateInput 时更新。如果我在 QML Converter 元素中添加注释,则更新工作正常。

使用 QML 转换器,QML 运行时识别对 rate 属性的依赖,并在 rate 更改时重新评估交换函数。如何向 QmlEngine 指示在 C++ 版本中执行相同操作?

【问题讨论】:

  • 关于 exchangeChanged 信号的情况,每次发出信号时,将其值重新分配给 text 属性。它不像属性绑定机制那样干净,但它应该可以工作。我对这种行为感到惊讶。我从来没有像 function-result-changed 信号一样存在于 QML 中。我可以知道为什么会这样,但我希望其他人可以解释一下。
  • bindings can be of arbitrary complexity 开始,QML 运行时就可以解决这个问题是有道理的。它只是将绑定推到函数调用后面。如果它在 C++ 中如此简单……那就是 5 倍以上的代码行,只完成了一半的工作。

标签: c++ qt binding qml signals-slots


【解决方案1】:

目前没有办法做到这一点。

不过,我不认为像这样依赖重新评估的函数是一个好习惯。您应该在必要时显式调用它:

Connections {
    target: converter
    onRateChanged: output.text = converter.exchange(amountField.text)
}

或将 exchange() 转换为属性,并以声明方式而不是命令方式处理它(代码未完成或未测试):

class Convert : public QObject
{
    // ...
    Q_PROPERTY(double amount READ amount WRITE setAmount NOTIFY amountChanged)
    Q_PROPERTY(double exchange READ exchange NOTIFY exchangeChanged)

    // ...

public:
    double exchange() { return m_rate * m_amount; }

private:
    double m_rate;
    double m_amount;
};

然后您需要在适当的位置发出各种 *Changed 信号等。

【讨论】:

  • 我想使用 C++ 来提高性能,并计划在数百个绑定中隐式使用速率值。添加 onRateChanged 语法对于规模来说太多了,但我正在考虑交换属性而不是放弃并仅使用 QML 转换器模式。
  • 没有办法按照我的意愿去做,你是对的;我想要的不是 Qt 解决方案。我最终完全按照您所说的去做,公开一个属性并在依赖值发生变化时发出变化信号。实现非常简单。
猜你喜欢
  • 2016-03-02
  • 2013-01-14
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
  • 2017-05-26
  • 2011-12-18
  • 1970-01-01
  • 2014-02-02
相关资源
最近更新 更多