Home > OS >  Efficient way to switch pyside6 qml screens
Efficient way to switch pyside6 qml screens

Time:07-18

I am working on a project where I have to make a multi-screen/window application. I am using QML and PySide6 for this purpose. The flow of my applications is like below:

login screen -> search screen (search for certain items) -> test screen (performs some operations) -> reports screen (displays results from test screen).

Currently what I am doing is using a main.py file to load the login page:

import os
from pathlib import Path
import sys
from api_login_test import get_credentials
# from login_data import get_credentials

from PySide6.QtCore import QCoreApplication, Qt, QUrl, QObject
from PySide6.QtWidgets import QApplication, QLineEdit, QPushButton
from PySide6.QtQml import QQmlApplicationEngine

CURRENT_DIRECTORY = Path(__file__).resolve().parent


def main():
    app = QApplication(sys.argv)
    engine = QQmlApplicationEngine()

    credentials = get_credentials()

    engine.rootContext().setContextProperty('credentials', credentials)
    login_file = os.fspath(CURRENT_DIRECTORY / "qml" / "login.qml")
    url = QUrl.fromLocalFile(login_file)

    def handle_object_created(obj, obj_url):
        if obj is None and url == obj_url:
            QCoreApplication.exit(-1)

    engine.objectCreated.connect(handle_object_created, Qt.QueuedConnection)
    engine.load(url)
    
    sys.exit(app.exec())


if __name__ == "__main__":
    main()

once the login page opens up now for switching rest of the screens, I use javascript function I wrote in all my qml files to switch to next screen. Following is the JS code I am using for switching to next screen.

function switch_to_test(access)   {
                if (access == true) {
                    var component = Qt.createComponent("test_interface_dark_debug.qml")
                    var win = component.createObject()
                    win.show()
                    visible = false
                    }
                else {
                    console.log('Invalid Credentials')
                }
                }

And this is causing my UI to crash as I reach test screen. So is there a way to efficiently switching the screens without my UI crashing? I found out this explanation for the crashing of my UI, but I don't know how to resolve the issue. Thank you

CodePudding user response:

The following is a showcase of various approaches regarding to your question.
Although all the code here is coherent and meant to be run together, It shows different approaches to navigate pages and you may adopt what you like.

Setup:

File main.py:

import sys
from pathlib import Path
from PySide6.QtGui import QGuiApplication
from PySide6.QtQml import QQmlApplicationEngine


if __name__ == "__main__":
    app = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    qml_file = Path(__file__).parent / "main.qml"
    engine.load(qml_file)

    if not engine.rootObjects():
        sys.exit(-1)

    sys.exit(app.exec())

Method 1: Use a StackView:

File main.qml:

import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material 2.15

ApplicationWindow {
    id: mainFrame
    width: 640
    height: 480
    visible: true
    title: qsTr("Windows handeling in QML")
    Material.theme: Material.Dark

    StackView{id: stack_view
        initialItem: logginWin
        anchors.fill: parent;
        Component{id: logginWin
            LoginWin{
                onLoggedIn: {
                    stack_view.push("./StackLayoutWin.qml")
                    console.log("logged In")
                }
            }
        }
    }
}

File LoginWin.qml:

import QtQuick
import QtQuick.Controls
import QtQuick.Controls.Material 2.15

Item{id: root
    anchors.fill: parent;
    signal loggedIn;

    TextArea{id: input_
        placeholderText: "Enter password"
        anchors.centerIn: parent
    }
    Button{
        text: "Login";

        anchors {
            horizontalCenter: parent.horizontalCenter;
            top: input_.bottom
        }
        onClicked: {
            console.log(input_.text)

            if(input_.text == "12345")
            {
                root.loggedIn()
            }
            else{
                input_.text = "Wrong password"
            }
        }
    }
}
Pros Cons
Default animation You will have to pop / append windows while navigating, That makes it inconvenient for multi-directional pages workflow.
Very easy for one direction pages workflow that also can be reversed.

Method 2:

Here would be our "main application" window.
You would have here different pages the user would be able to navigate.

File StackLayoutWin.qml:

import QtQuick
import QtQuick.Controls 
import QtQuick.Layouts
import QtQuick.Controls.Material 2.15

Item{
    Button{id: return_to_StackView
        anchors{
            top: parent.top
            right: parent.right
        }
        text: "return to login page"
        onClicked: {
            stack_view.pop()
        }
    }
    
    StackLayout {
        id: layout
        anchors.top: return_to_StackView.bottom
        width: parent.width;
        height: parent.height;
        currentIndex: 1
        Rectangle {
            color: 'teal'
            implicitWidth: 200
            implicitHeight: 200
        }
        Rectangle {
            color: 'plum'
            implicitWidth: 300
            implicitHeight: 200
        }
    }
}

You can find this example here

  • Related