Reloading QQuickWindow content without window recreation



  • For qml file with Item element as root of qml scene:

    Item {
    ...
    }
    

    it is possible to preview qml file content with QQuickView without window recreation - see relevant slightly modified and simplified qmlscene code:

    QQmlEngine engine;
    QPointer<QQmlComponent> component = new QQmlComponent(&engine);
    QQuickWindow *window = nullptr;
    auto qxView = new QQuickView(&engine, nullptr);
    
    ...
    
    // Call this slot on file update (for example by QFileSystemWatcher signal)
    updatePreview()
    {
        // Recreate Qml Component
        engine.clearComponentCache();
        component = new QQmlComponent(&engine);
        component->loadUrl(url);
        QObject *topLevel = component->create();
        
        // Recreate Quick Window
        window = qobject_cast<QQuickWindow *>(topLevel);
        if (window) {
            engine.setIncubationController(window->incubationController());
        } else {
            QQuickItem *contentItem = qobject_cast<QQuickItem *>(topLevel);
            if (contentItem) {
                window = qobject_cast<QQuickWindow *>(qxView);
                delete qxView->rootObject(); // Clear old root object before setting new one                
                qxView->setContent(url, component, contentItem);
            }
        }
    }
    

    For such qml file structure window become nullptr on Quick Window recreation and execution goes to else path of if statement. And there we use single QQuickView instance - qxView, just modifying its content without full reloading and recreation.

    BTW, QQuickView::setContent() is undocumented but used in qmlscene.

    However if qml file contains ApplicationWindow as root item of the scene:

    ApplicationWindow {
    ...
    }
    

    execution goes by the 1st variant of Quick Window recreation:

    engine.setIncubationController(window->incubationController());
    

    and new QQuickWindow instance created which takes much more time and force us to destroy and close previous one.

    Is it possible analogous to QQuickView reload scene content for QQuickWindow without full window recreation? Thanks!


  • Qt Champions 2017

    One way to look at this is - without window creation

    1. QQuickWIndow gives the invisible root item of the scene using contentItem function.

    2. I can just create the item based QML object and attach this to content item(invisible root item).

    3. This way we will not re-create the window, but just create the scene items and attach item to invisibleItem.



  • @dheerendra I'd tried to use contentItem() with no luck. Could You provide minimum working sample or few lines of code to clarify the idea please? How to create QML object from file containing ApplicationWindow element?


  • Qt Champions 2017

    Just check this..

    ======main.cpp====

    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
        if (engine.rootObjects().isEmpty())
            return -1;
    
        qDebug() << engine.rootObjects().at(0)->objectName() <<endl;
        QObject *obj = engine.rootObjects().at(0);
        qDebug() << " Class Name =" << obj->metaObject()->className() <<endl;
    
        QQuickWindow *w = qobject_cast<QQuickWindow*>(obj);
        qDebug() << w->objectName() <<endl;
    
        QQuickItem *rootItem = w->contentItem();
    
        QQmlComponent *comp = new QQmlComponent(&engine,QUrl(QStringLiteral("qrc:/ChildItem.qml")));
        if(comp->isError()){
           qWarning() << Q_FUNC_INFO << " Unable to create the component " << comp->errorString() << endl;
           return 1;
        }
        QObject *o1 = comp->create();
        QQuickItem *childItem = qobject_cast<QQuickItem*>(o1);
        childItem->setParentItem(rootItem);
    
        return app.exec();
    }
    

    ===main.qml=======

    Window {
        visible: true
        width: 440
        height: 480
        title: qsTr("Hello World")
        objectName: "TopW"
    }
    

    ===========ChildItem.qml=========

    Rectangle {
        width: 400;height: 400;color: "red"
        Component.onCompleted: {
            console.log("Child Item created")
        }
    }
    


  • @dheerendra this not I'd like to achieve: You propose me to change ApplicationWindow content under root item. But I need to track qml changes in a file which contains whether qml Item (which works fine without reloading) or ApplicationWindow. For example I have such file from tutorial:

    import QtQuick 2.11
    import QtQuick.Controls 2.4
    import QtQuick.Controls.Material 2.4
    import QtQuick.Layouts 1.11
    import QtQuick.Window 2.11
    import Qt.labs.calendar 1.0
    
    ApplicationWindow {
        id: window
        width: 400
        height: 600
        visible: true
        color: "red"
    
        ListView {
            id: alarmListView
            anchors.fill: parent
        }
    
        RoundButton {
            id: addAlarmButton
            text: "+"
            anchors.bottom: alarmListView.bottom
            anchors.bottomMargin: 8
            anchors.horizontalCenter: parent.horizontalCenter
            onClicked: alarmDialog.open()
        }
    }
    

    and here I can change color, add, delete or modify items, dimension (width, height), etc. And see all this changes in real time without Window recreation like for QQuickView. For now it recreates and reloads QQuickWindow on every file change and need to close and delete old one.


  • Qt Champions 2017

    @Aleksey_K-0
    This is where I'm proposing to split the AppWIndows and Content separately. You change the content qml. It will update your AppWindow as well. In the QML what you have posted let me know what you would like to achieve with example. There are ways to monitor the changes.



  • @dheerendra https://github.com/penk/qml-livereload - this is what I try to achieve: live QML reload on file change. QQuickView works here without window recreation - just changed content, ApplicationWindow and QQuickWindow forces to recreate Window on every file change which I try to avoid.

    This is where I'm proposing to split the AppWIndows and Content separately.

    Not clear how?

    You change the content qml. It will update your AppWindow as well. In the QML what you have posted let me know what you would like to achieve with example.

    I mention above: edit file and see results in real time on preview application like qmlscene.

    There are ways to monitor the changes.

    What are they?


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.