Динамическая загрузка и выгрузка 2 qml файлов из cpp - PullRequest
0 голосов
/ 18 апреля 2020

У меня есть требование запустить 2 разных файла Qml "mainwindow.qml" и "basi c .qml", когда оба они независимы друг от друга.

Изначально мне нужно запустить окно qml на основе flag bSettingMainWindow, на основании этого я буду запускать любой файл qml.

После запуска мне нужно в любое время переключаться между этими 2 файлами qml. Это должно быть похоже на загрузку и выгрузку «mainwindow.qml» и «basi c .qml» в зависимости от действий пользователя. Так как из-за проблем с памятью, мне нужно загрузить любой из них одновременно. и я не хочу играть с видимым true или false.

, тогда как из этого кода ниже я могу загрузить любой файл qml на основе флага bSettingMainWindow. а также после загрузки я могу переключиться в другое окно файла qml.

Предположим, что сначала я запустил файл Mainwindow.qml, затем щелкнул мышью на прямоугольнике mainwindow.qml и перешел на basi c. qml и теперь, если я нажимаю на прямоугольник basi c .qml, он не переключается на 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()
            }
        }
    }
}

Ответы [ 2 ]

1 голос
/ 18 апреля 2020

Это так просто в QML. !!! Вам не нужно создавать свой собственный загрузчик окон, так как в QML уже есть Loader. рассмотрим этот образец. Надеюсь, это сработает для вас.

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.qr c

<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

backendcppclass. 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();
}

И Basi c .qml и mainwindow.qml могут быть вашими пользовательскими спецификациями c qmls .

1 голос
/ 18 апреля 2020

Загрузка и выгрузка всего окна не даст хорошего опыта пользователя. Если у вас есть проблемы с памятью и вы не хотите использовать свойство видимости, вы можете попробовать с Loader концепциями.

Я попробовал приведенный ниже пример кода, он работает. Основываясь на флаге bool, я попытался переключиться между windows. Пожалуйста, проверьте образец ниже. Я надеюсь, что это поможет решить вашу проблему.

/* 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
    }
}
...