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

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

本文关键字:C++ 执行 QML 插槽 情况下 信号      更新时间:2023-10-16

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

目前,我在C++类中声明了一个信号:

signals:
void testSignal();

QML对象中的信号/插槽:

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

然后我连接这两个:

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

但正如我所看到的,这并不干净:

  1. 事实上,这是一个奇怪的SIGNAL/SIGNAL连接
  2. 由于性能和长代码的原因,我不想使用SIGNAL/SLOT机制,除非迫不得已

是否有直接从QObject执行QMLonExecuteTestFunc();的方法?

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

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回调

如果你真的坚持避免信号/插槽(尽管我不明白为什么;Qt和QML是围绕它构建的,试图避免它是在对抗框架,而不是使用它的优势(,还有另一种方法。您可以在向QML公开的C++对象上创建QJSValue类型的属性。然后,在C++on设置中,检查设置的内容是否可调用(使用QJSValue::isCallable()(。然后,作为要触发QML中要执行的任何内容的点,使用QJSValue::call调用它。

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

反模式:QMetaObject::invokeMethod

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