我有多个通过 StackView 推送的 qml 文件.如何将它们连接到 C++

2022-01-19 00:00:00 qt qml c++ interaction stackview

我的项目包含 6 个 qml 文件: main.qml 打开一个新的 ApplicationWindow 并声明工具栏.它还使用 initalItem homescreen.qml 初始化 StackView.在主屏幕上,我有不同的按钮,通过 stack.push("URL") 打开不同的 qml 文件.除了 main.qml,所有文件都以 Item{} 开头.我已经能够连接来自 main.qml 和 home.qml 的信号.但是我一直无法访问堆栈中更深的对象.我不知道我是否需要更改我的 .cpp 代码以访问其他对象,或者我是否应该更改 StackView 的初始化,以便在开始时加载和访问所有文件.这是代码,分解为最基本的:

My Projects contains 6 qml Files: The main.qml opens a new ApplicationWindow and declares the toolbar. It also initalizes StackView with the initalItem homescreen.qml. On the Home Screen I have different buttons which open different qml Files, via stack.push("URL"). Besides the main.qml all Files start with Item{}. I've been able to connect signals from the main.qml and the home.qml. But I've been unable to access Objects that are deeper in the stack. I don't know if I hvae to change my .cpp code to access the other objects, or if I should change the Initalization of StackView, so that all Files are loaded and accessible at the beginning. Here is the code, broke down to the very basics:

  • main.qml

  • main.qml

ApplicationWindow {
      Rectangle{
                id: homeButton
                objectName: "homeButton"
                signal qmlSignal(string msg)
                MouseArea {
                     onClicked:  {stack.push({item:"qrc:/home.qml}); homeButton.qmlSignal("Hello")}
                }
      }
      StackView{
           initalItem: "qrc:/home.qml"
      }

}

secondframe.qml//主屏幕之后的随机 qml 文件

secondframe.qml // A randomw qml File that comes after the Home Screen

Item {
      Rectangle{
                id: test
                objectName: "test"
                signal qmlSignal(string msg)
                MouseArea {
                     onClicked:  {stack.push({item:"qrc:/thirdframe.qml}); test.qmlSignal("Hello")}
                }
      }
}

  • main.cpp

  • main.cpp

    QApplication app (argc, argv);
    QQmlEngine enigne;
    QQmlComponent component(&engine, QUrl(QStringLiteral("qrl:/main.qml")));
    QObject *object = componet.create();
    QQmlComponent newcomponent(&engine, QUrl(QStringLiteral("qrl:/secondframe.qml")));
    QObject *newobject = newcomponet.create();
    
    MyClass myClass
    QObject *home = object->findChild<QObject*>("homeButton");    // I'm able to connect to every Object in the main.qml or home.qml
    QObject::connect(home,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString)));
    QObject *test = newobject->findChild<QObject*>("test");       // Can't connect to the Objects in secondframe.qml
    QObject::connect(test,SIGNAL(qmlSignal(Qstring)), &myClass, SLOT(cppSlot(QString)));
    

  • 推荐答案

    比进入 QML 树并提取可能存在或不存在的对象更好的方法是向 QML 提供基于 C++ 的 API.

    A way better approach than to reach into the QML tree and pull out objects that might or might not be there is to provide C++ based API to QML.

    1. 创建一个基于 QObject 的类,该类具有 QML 需要能够作为插槽或 Q_INVOKABLE

    class MyAPI : public QObject
    {
        Q_OBJECT
    public slots:
        void cppSlot(const QString &text);
    };
    

  • 创建一个实例并将其公开给 QML

  • Create an instance of that and expose it to QML

    MyAPI myApi;
    QQmlEngine engine;
    engine.rootContext()->setContextProperty("_cppApi", &myApi);
    

  • 在 QML 中使用,好像_cppApi"是一个对象 id

  • Use in QML as if "_cppApi" is an object id

    MouseArea {
         onClicked:  {stack.push({item:"qrc:/thirdframe.qml}); _cppApi.cppSlot("Hello")}
    }
    

  • 相关文章