如何在没有信号的情况下从 C++ 执行 QML 槽?

How to execute QML slot from C++ without a signal?

我得到了一个 QObject 形状的 QML 对象。使用 ->setProperty(..., ...) 我可以更改属性,但是如何在没有信号的情况下执行插槽?

目前我在我的 C++ 中声明了一个信号 class:

signals:
  void testSignal();
QML 对象中的

和 signal/slot:

signal executeTestFunc(); onExecuteTestFunc: {
  testAnimation.start();
}

然后我连接这两个:

QObject::connect(this, SIGNAL(testSignal()),
                 QmlObject, SIGNAL(executeTestFunc()));

但这并不干净,如我所见:

  1. 事实上这是奇怪的SIGNAL/SIGNAL连接。
  2. 我不想使用 SIGNAL/SLOT 机制,除非我不得不使用,因为性能和长代码。

有没有办法直接从 QObject 执行 QML onExecuteTestFunc();

您可以创建一个将发出信号的 C++ class。该信号将被 QML 捕获。不需要显式 connection 和 SIGNAL/SLOT。示例:

C++:

class Presenter : public QObject
{
    Q_OBJECT
public:
    explicit Presenter()
    {
        QTimer *timer = new QTimer();
        timer->setInterval(500);
        connect(timer, &QTimer::timeout,
                this, &Presenter::timeout);
        timer->start();
    }

    Q_SIGNAL void timeout();
};

QML:

Window {
    ...
    Presenter {
        onTimeout: {
            console.log("called from c++")
        }
    }
}

结果:

qml: called from c++
qml: called from c++
qml: called from c++
qml: called from c++
...

@Thomenson 已经就如何连接到来自 C++ 的信号并在 QML 中对其进行操作给出了很好的答案。如果您可以从 QML 创建 C++,他的解决方案就有效,但情况可能并非总是如此。

连接元素

您还可以考虑另外两个选项。首先,如果您有一个不是从 QML 创建但以其他方式放入其中的对象(QML 上下文、静态对象、从可调用对象返回...),您可以使用 Connections 元素:

Connections {
    target: theObjectWithTheSignal
    onSignalName: {doSomething();}
}

这是一种灵活的方式来响应来自您不是在 QML 中创建的对象的信号,甚至是在 QML 中其他地方创建的对象。

回调使用JSValue

如果你真的坚持要避免 signal/slot(虽然我不明白为什么;Qt 和 QML 是围绕它构建的并且试图避免它是在对抗框架而不是利用它的优势),那里是另一种方式。您可以在公开给 QML 的 C++ 对象上创建类型 QJSValue 的 属性。然后,在 C++ 中设置时,检查设置的内容是否可调用(使用 QJSValue::isCallable())。然后作为你希望触发任何你想在你的 QML 中执行的点,使用 QJSValue::call.

调用它

在 QML 方面,您可以简单地分配或绑定可调用的内容,就像您为信号处理程序所做的那样。

反模式:QMetaObject::invokeMethod

还有另一种方法,我只会将其作为反模式的警告。您可以 使用 Qt 的内省机制从 C++ 调用 QML。您可以通过设置 objectName 找到一个对象,并使用 QMetaObject::invokeMethod 对其调用任何(可调用的)方法,读取和写入任何 属性 并监听所有信号。这包括调用您在 QML 中定义的方法。使用它,您可以从 C++ 操作 QML。 不要这样做。它会导致代码不灵活且难以维护。