如何在没有信号的情况下从 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()));
但这并不干净,如我所见:
- 事实上这是奇怪的SIGNAL/SIGNAL连接。
- 我不想使用 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。 不要这样做。它会导致代码不灵活且难以维护。
我得到了一个 QObject
形状的 QML 对象。使用 ->setProperty(..., ...)
我可以更改属性,但是如何在没有信号的情况下执行插槽?
目前我在我的 C++ 中声明了一个信号 class:
signals:
void testSignal();
QML 对象中的 和 signal/slot:
signal executeTestFunc(); onExecuteTestFunc: {
testAnimation.start();
}
然后我连接这两个:
QObject::connect(this, SIGNAL(testSignal()),
QmlObject, SIGNAL(executeTestFunc()));
但这并不干净,如我所见:
- 事实上这是奇怪的SIGNAL/SIGNAL连接。
- 我不想使用 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。 不要这样做。它会导致代码不灵活且难以维护。