【问题标题】:Dynamically loading and unloading 2 qml files from cpp从cpp动态加载和卸载2个qml文件
【发布时间】:2020-08-01 01:25:27
【问题描述】:

我需要启动 2 个不同的 Qml 文件“mainwindow.qml”和“basic.qml”,而这两个文件是相互独立的。

最初我需要基于标志 bSettingMainWindow 启动 qml 窗口,基于此我将启动任何一个 qml 文件。

启动后,我需要随时在这 2 个 qml 文件之间切换。它应该像加载和卸载“mainwindow.qml”和“basic.qml”,基于用户操作。 因为因为内存问题,我需要一次加载它们中的任何一个。而且我不想玩可见的真假。

而从下面的代码中,我可以加载任何一个基于标志 bSettingMainWindow 的 qml 文件。以及加载后 我可以切换到另一个 qml 文件窗口。

假设我首先在 Mainwindow.qml 中启动,然后我在 mainwindow.qml 的 Rectangle 上单击鼠标按钮并移动到 basic.qml,现在如果我单击 basic.qml 的 Rectangle 它不是 切换到 mainwindow.qml。 反之亦然。 只有一次我可以在这 2 中切换黑白。我想多次切换。 以下是代码,请提供您的答案

//** windowLoader.hpp   **//
class WindowLoader : public QObject{
    Q_OBJECT
    QQmlApplicationEngine loadQMlEngine;

public:
    explicit WindowLoader(QObject * parent = 0);
    void loadWindow();


public slots:
    void loadMainWindow();
    void loadBasicWindow();
    void connectToMain(QObject *object = nullptr, const QUrl &url = QUrl(""));
    void connectToBasic(QObject *object = nullptr, const QUrl &url = QUrl(""));

    private:
};

//** windowLoader.cpp   **//
WindowLoader::WindowLoader(QObject *parent) : QObject(parent) {

}

void WindowLoader::loadWindow()  {
    if(bSettingMainWindow){ //this will be from a internal flag, this check is only one time during launch
        connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToBasic(QObject *, const QUrl &)),Qt::QueuedConnection);
        loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
        loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));
    } else {
        connect(&loadQMlEngine,SIGNAL(objectCreated(QObject *, const QUrl &)),this,SLOT(connectToMain(QObject *, const QUrl &)),Qt::QueuedConnection);
        loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
        loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));     
    }
}

void WindowLoader::connectToBasic(QObject *object, const QUrl &url) {
    if(object){
        connect(object, SIGNAL(switchToBasicSignal()), this, SLOT(loadBasicWindow()));
    }
}

void WindowLoader::connectToMain(QObject *object, const QUrl &url) {
    if(object){
        connect(object, SIGNAL(switchToMainSignal()), this, SLOT(loadMainWindow()));
    }
}

void WindowLoader::loadBasicWindow() {
    loadQMlEngine.rootObjects()[0]->deleteLater();
    loadQMlEngine.destroyed();

    loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/basic.qml")));
}

void WindowLoader::loadMainWindow() {
    loadQMlEngine.rootObjects()[0]->deleteLater();
    loadQMlEngine.destroyed();

    loadQMlEngine.rootContext()->setContextProperty( "interface", m_interface );
    loadQMlEngine.load(QUrl(QStringLiteral("qrc:/Qml/mainWindow.qml")));

}


//** main.cpp **//
int main( int argc, char *argv[] ) {
    QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    WindowLoader root;
    root.loadWindow();
    return app.exec();
}



// ** mainWindow.qml **//
ApplicationWindow {
    visible: true
    width: 1200
    height: 800
    title: qsTr("MainWindow")

    signal switchToBasicSignal()

    Rectangle {
        anchors.fill: parent
        MouseArea{
            anchors.fill: parent
            onClicked: {
                switchToBasicSignal()
            }
        }
    }
}

//** basic.qml **//
ApplicationWindow {
    visible: true
    width: 640
    height: 480
    title: qsTr("basic")

    signal switchToMainSignal()

    Rectangle {
        anchors.fill: parent
        MouseArea{
            anchors.fill: parent
            onClicked: {
                switchToMainSignal()
            }
        }
    }
}

【问题讨论】:

    标签: c++ qt qml qqmlapplicationengine


    【解决方案1】:

    加载和卸载整个窗口不会提供良好的用户体验。如果您有内存问题并且不想使用可见性属性,您可以尝试使用 Loader 概念。

    我已经尝试了下面的示例代码,它可以工作。基于 bool 标志,我尝试在窗口之间切换。请检查下面附上的样本。我希望这有助于解决您的问题。

    /* main.cpp */
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QQmlContext>
    
    #include "backend.h"
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        Backend backend(&engine);
    
        engine.rootContext()->setContextProperty("backend", &backend);
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    /* backend.h */
    #ifndef BACKEND_H
    #define BACKEND_H
    
    #include <QObject>
    
    class QQmlApplicationEngine;
    class Backend : public QObject
    {
        Q_OBJECT
    public:
        explicit Backend(QQmlApplicationEngine *engine, QObject *parent = nullptr);
    
        Q_INVOKABLE void changeWindow();
    
    private:
        QQmlApplicationEngine *_engine = nullptr;
        bool _main = true;
    };
    
    #endif // BACKEND_H
    

    /*backend.cpp*/
    #include "backend.h"
    #include <QQmlApplicationEngine>
    #include <QQuickWindow>
    
    Backend::Backend(QQmlApplicationEngine *engine, QObject *parent) : QObject(parent)
    {
        _engine = engine;
    }
    
    void Backend::changeWindow()
    {
        QObject *qObject = _engine->rootObjects().first();
        Q_ASSERT( qObject != NULL );
    
        QQuickWindow* mainWindow = qobject_cast<QQuickWindow*>(qObject);
        Q_ASSERT( mainWindow );
    
        _main = !_main;
        if (_main)
        {
            _engine->load(QUrl(QStringLiteral("qrc:/main.qml")));
        } else
        {
            _engine->load(QUrl(QStringLiteral("qrc:/samplewindow.qml")));
        }
        mainWindow->close();
        qObject->deleteLater();
    }
    

    /* main.qml */
    import QtQuick 2.9
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
    
        MouseArea {
            anchors.fill: parent
            onClicked: backend.changeWindow()
        }
    
        Text {
            text: qsTr("main window")
            anchors.centerIn: parent
        }
    }
    

    /* samplewindow.qml */
    import QtQuick 2.9
    import QtQuick.Window 2.2
    
    Window {
        visible: true
        width: 640
        height: 480
    
        MouseArea {
            anchors.fill: parent
            onClicked: backend.changeWindow()
        }
    
        Text {
            text: qsTr("sample window")
            anchors.centerIn: parent
        }
    }
    

    【讨论】:

      【解决方案2】:

      在 QML 中非常简单。!!!您不需要创建自己的窗口加载器,因为 QML 已经有加载器。考虑这个样本。希望这对你有用。

      main.cpp

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      #include <QQmlContext>
      #include "backendcppclass.h"
      
      int main(int argc, char *argv[])
      {
          QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
      
          QGuiApplication app(argc, argv);
      
          QQmlApplicationEngine engine;
          BackendCPPClass backendCPPClass; /// create instance of backend class.
          engine.rootContext()->setContextProperty("backend", &backendCPPClass); /// Set context propert so that we can access in QML.
      
          const QUrl url(QStringLiteral("qrc:/main.qml"));
          QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                           &app, [url](QObject *obj, const QUrl &objUrl) {
              if (!obj && url == objUrl)
                  QCoreApplication::exit(-1);
          }, Qt::QueuedConnection);
          engine.load(url);
      
          return app.exec();
      }
      

      main.qml

      import QtQuick 2.14
      import QtQuick.Window 2.14
      
      Window {
          visible: true
          width: 640
          height: 480
          Loader {
              id: windowLoader
              anchors.fill: parent
              source: backend.bSettingMainWindow ? "qrc:/mainwindow.qml" : "qrc:/basic.qml"
          }
      }
      

      qml.qrc

      <RCC>
          <qresource prefix="/">
              <file>main.qml</file>
              <file>basic.qml</file>
              <file>mainwindow.qml</file>
          </qresource>
      </RCC>
      

      backendcppclass.h

      #ifndef BACKENDCPPCLASS_H
      #define BACKENDCPPCLASS_H
      
      #include <QObject>
      
      class BackendCPPClass : public QObject
      {
          Q_OBJECT
      public:
          explicit BackendCPPClass(QObject *parent = nullptr) {};
          Q_PROPERTY(MEMBER bSettingMainWindow NOTIFY bSettingMainWindowChanged)
      
      signals:
          void bSettingMainWindowChanged();
      
      private:
          bool bSettingMainWindow = false;
      
      };
      
      #endif // BACKENDCPPCLASS_H
      

      后端cppclass.cpp

      #include "backendcppclass.h"
      
      BackendCPPClass::BackendCPPClass(QObject *parent) : QObject(parent)
      {
          /// update any logic to change the variable bSettingMainWindow.
          /// QML will automatically validate it.
          bSettingMainWindow = true;
          emit bSettingMainWindowChanged();
      }
      

      Basic.qml 和 mainwindow.qml 可以是您自定义的特定 qml。

      【讨论】:

        猜你喜欢
        • 2019-06-02
        • 2012-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多