简体   繁体   English

关闭另一个窗口后如何重新打开?

[英]How to reopen window after closing other one?

I work on qml-based application.我从事基于 qml 的应用程序。

Environment:环境:

  • Windows 10 64bit视窗 10 64 位
  • Python3.7 Python3.7
  • PyQt5 PyQt5
  • Qt 5.13.1 Qt 5.13.1
  • Build & Run: Desktop Qt 5.13.1 MSVC2015 64bit构建和运行:桌面 Qt 5.13.1 MSVC2015 64 位

I'd like to have the following behaviour:我想有以下行为:

  • Initially, there is shown Login window.最初,显示登录窗口。
  • After getting access token the Login page closes and General window opens.获得访问令牌后,登录页面关闭并打开常规窗口。
  • After closing the General window Login window opens again.关闭 General 窗口后,Login 窗口再次打开。
  • After closing the Login window (literally, if I have no access token after closing the Login window) my program finishes.关闭登录窗口后(字面上,如果关闭登录窗口后我没有访问令牌)我的程序就完成了。

Now I have the following issue after closing Login window without access token (login.res_token == ""):现在,在没有访问令牌的情况下关闭登录窗口后出现以下问题(login.res_token == ""):

The program has unexpectedly finished.
The process was ended forcefully.
...\Python\Python37\python.exe crashed.

A piece of main.py:一段main.py:

def init_app():
    app_login = QGuiApplication(sys.argv)
    engine = QQmlApplicationEngine()

    manager = ComponentCacheManager(engine)
    context = engine.rootContext()
    context.setContextProperty("componentCache", manager)

    current_path = os.path.abspath(os.path.dirname(__file__))
    qml_file = os.path.join(current_path, 'ui/LoginPage.qml')
    engine.load(qml_file)

    login = Login()
    engine.rootContext().setContextProperty("login", login)

    win = engine.rootObjects()[0]

    win.show()

    app_login.exec_()

    if(login.res_token != ""):
        main_app = QGuiApplication(sys.argv)
        engine = QQmlApplicationEngine()

        manager = ComponentCacheManager(engine)
        context = engine.rootContext()
        context.setContextProperty("componentCache", manager)

        current_path = os.path.abspath(os.path.dirname(__file__))
        qml_file = os.path.join(current_path, 'ui/GeneralPage.qml')
        engine.load(qml_file)

        engine.rootContext().setContextProperty("access_token", login.res_token)

        win = engine.rootObjects()[0]

        win.show()
        main_app.exec_()
        init_app()
    else:
        sys.exit()

if __name__ == "__main__":
    init_app()

However, if I code in another way (without recursion), this action works correctly.但是,如果我以另一种方式进行编码(不使用递归),则此操作可以正常工作。 For example:例如:

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

    manager = ComponentCacheManager(engine)
    context = engine.rootContext()
    context.setContextProperty("componentCache", manager)

    current_path = os.path.abspath(os.path.dirname(__file__))
    qml_file = os.path.join(current_path, 'ui/LoginPage.qml')
    engine.load(qml_file)

    login = Login()
    engine.rootContext().setContextProperty("login", login)

    win = engine.rootObjects()[0]

    win.show()

    app_login.exec_()

    if(login.res_token != ""):
        main_app = QGuiApplication(sys.argv)
        engine = QQmlApplicationEngine()

        manager = ComponentCacheManager(engine)
        context = engine.rootContext()
        context.setContextProperty("componentCache", manager)

        current_path = os.path.abspath(os.path.dirname(__file__))
        qml_file = os.path.join(current_path, 'ui/GeneralPage.qml')
        engine.load(qml_file)

        engine.rootContext().setContextProperty("access_token", login.res_token)

        win = engine.rootObjects()[0]

        win.show()
        main_app.exec_()
    else:
        sys.exit()

But here I don't reopen Login window after closing General window.但是在这里我没有在关闭常规窗口后重新打开登录窗口。

If I write something like that, the program crashes after closing General window with the same error:如果我写这样的东西,程序会在关闭常规窗口后崩溃并出现相同的错误:

if __name__ == "__main__":
    while(True):
        app_login = QGuiApplication(sys.argv)
        engine = QQmlApplicationEngine()

        manager = ComponentCacheManager(engine)
        context = engine.rootContext()
        context.setContextProperty("componentCache", manager)

        current_path = os.path.abspath(os.path.dirname(__file__))
        qml_file = os.path.join(current_path, 'ui/LoginPage.qml')
        engine.load(qml_file)

        login = Login()
        engine.rootContext().setContextProperty("login", login)

        win = engine.rootObjects()[0]

        win.show()

        app_login.exec_()

        if(login.res_token != ""):
            main_app = QGuiApplication(sys.argv)
            engine = QQmlApplicationEngine()

            manager = ComponentCacheManager(engine)
            context = engine.rootContext()
            context.setContextProperty("componentCache", manager)

            current_path = os.path.abspath(os.path.dirname(__file__))
            qml_file = os.path.join(current_path, 'ui/GeneralPage.qml')
            engine.load(qml_file)

            engine.rootContext().setContextProperty("access_token", login.res_token)

            win = engine.rootObjects()[0]

            win.show()
            main_app.exec_()
        else:
            break
    sys.exit()

How will it be better to resolve this problem?如何更好地解决这个问题?

The logic is to use the signals to notify the changes and in the logical part to change the page逻辑是使用信号通知更改并在逻辑部分更改页面

import os

from PyQt5 import QtCore, QtGui, QtQml


class AuthenticationManager(QtCore.QObject):
    login_signal = QtCore.pyqtSignal()
    logout_signal = QtCore.pyqtSignal()

    def __init__(self, parent=None):
        super().__init__(parent)
        self._token = ""

    @QtCore.pyqtProperty(str, constant=True)
    def token(self):
        return self._token

    @QtCore.pyqtSlot(str, str, result=bool)
    def login(self, username, password):
        self._token = self._get_token(username, password)
        if self.token:
            self.login_signal.emit()
            return True
        return False

    @QtCore.pyqtSlot()
    def logout(self):
        self._token = ""
        self.logout_signal.emit()

    def _get_token(self, username, password):
        "emulate token"
        if username == "user" and password == "pass":
            return "Token"
        return ""


class WindowManager(QtCore.QObject):
    def __init__(self, parent=None):
        super().__init__(parent)

        self._current_page = ""

        self._engine = QtQml.QQmlApplicationEngine()

        self._authentication = AuthenticationManager()
        self._authentication.login_signal.connect(self.on_login_signal)
        self._authentication.logout_signal.connect(self.on_logout_signal)

        self._engine.rootContext().setContextProperty(
            "authentication", self._authentication
        )

    def init(self):
        self.on_logout_signal()

    def on_login_signal(self):
        self.current_page = "ui/GeneralPage.qml"

    def on_logout_signal(self):
        self.current_page = "ui/LoginPage.qml"

    @property
    def current_page(self):
        return self._current_page

    @current_page.setter
    def current_page(self, page):
        self._current_page = page
        current_dir = os.path.abspath(os.path.dirname(__file__))
        qml_file = os.path.join(current_dir, self.current_page)
        self._engine.load(qml_file)


if __name__ == "__main__":
    import sys

    app = QtGui.QGuiApplication(sys.argv)
    manager = WindowManager()
    manager.init()
    sys.exit(app.exec_())

LoginPage.qml登录页面.qml

import QtQuick 2.13
import QtQuick.Controls 2.13 

ApplicationWindow {
    id: root
    visible: true
    width: 640
    height: 480
    title: "Login Page"

    Row{
        TextField {
            id: username
            placeholderText: qsTr("Enter name")
        }
        TextField {
            id: password
            placeholderText: qsTr("Enter password")
            echoMode: TextInput.Password
        }
        Button{
            text: "Login"
            onClicked: {
                if(authentication.login(username.text, password.text)){
                    console.log("token:", authentication.token)
                    root.close()
                }
            }
        }
    }
}

GeneralPage.qml通用页面.qml

import QtQuick 2.13
import QtQuick.Controls 2.13 

ApplicationWindow {
    id: root
    visible: true
    width: 640
    height: 480
    title: "General Page"
    Button{
        text: "Logout"
        onClicked: close()
    }
    onClosing: authentication.logout()
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM