首页 > 解决方案 > 可以在 C++ QObject::connect() 中连接 QML 对象现有信号吗?

问题描述

QML TreeView 有一个名为:doubleClicked(QModelIndex) 的信号

参考:https ://doc.qt.io/qt-5.10/qml-qtquick-controls-treeview.html#doubleClicked-signal

它可能在 C++ QObject::connect() 中连接现有信号?

我试过这个:

QQmlApplicationEngine engine;
QObject *myTreeMenu = engine.rootObjects().at(0)->findChild<QObject*>("myTreeMenu");
connect(myTreeMenu , SIGNAL(doubleClicked(QModelIndex)), this, SLOT(slotModelClicked(QModelIndex)));

但我收到此返回错误:

QObject::connect: No such signal TreeView_QMLTYPE_63_QML_68::doubleClicked(QModelIndex) in '...'
QObject::connect:  (sender name:   'myTreeMenu ')

标签: c++qtqmlsignals-slots

解决方案


Qt 5.11的文档解释了为什么这不是使用 C++ 和 QML 的最佳方式。我建议您改为公开一个插槽或Q_INVOKABLE在您的 C++ 对象中并在处理程序中调用它onDoubleClicked

Q_INVOKABLE void doStuff();

在 QML 中:

onDoubleClicked: cppObject.doStuff()

该文档有一个“之前和之后”示例来证明这一点;这是其中的大部分:

使用这种方法,对对象的引用是从 QML 中“拉出”的。问题在于 C++ 逻辑层依赖于 QML 表示层。如果我们以 objectName 更改的方式重构 QML,或者某些其他更改破坏了 C++ 查找 QML 对象的能力,我们的工作流程将变得更加复杂和乏味。

重构 QML 比重构 C++ 容易得多,所以为了让维护无痛,我们应该尽量让 C++ 类型不知道 QML。这可以通过将 C++ 类型的引用“推送”到 QML 中来实现:

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Backend backend;

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("backend", &backend);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

然后 QML 直接调用 C++ 槽:

import QtQuick 2.11
import QtQuick.Controls 2.4

Page {
    Button {
        text: qsTr("Restore default settings")
        onClicked: backend.restoreDefaults()
    }
}

使用这种方法,如果将来需要重构 QML,C++ 将保持不变。

在上面的示例中,我们在根上下文上设置了一个上下文属性,以将 C++ 对象公开给 QML。这意味着该属性可用于引擎加载的每个组件。上下文属性对于加载 QML 后必须立即可用且无法在 QML 中实例化的对象很有用。

集成 QML 和 C++演示了另一种方法,其中 QML 可以识别 C++ 类型,以便它可以自己实例化它。


推荐阅读