0

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

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

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

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

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

//** 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()
            }
        }
    }
}
4

2 回答 2

2

加载和卸载整个窗口不会提供良好的用户体验。如果您有内存问题并且不想使用可见性属性,您可以尝试使用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
    }
}
于 2020-04-18T17:05:48.403 回答
2

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

主文件

#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>

后端cppclass.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。

于 2020-04-18T18:34:45.417 回答