繁体   English   中英

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

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

我从事基于 qml 的应用程序。

环境:

  • 视窗 10 64 位
  • Python3.7
  • PyQt5
  • Qt 5.13.1
  • 构建和运行:桌面 Qt 5.13.1 MSVC2015 64 位

我想有以下行为:

  • 最初,显示登录窗口。
  • 获得访问令牌后,登录页面关闭并打开常规窗口。
  • 关闭 General 窗口后,Login 窗口再次打开。
  • 关闭登录窗口后(字面上,如果关闭登录窗口后我没有访问令牌)我的程序就完成了。

现在,在没有访问令牌的情况下关闭登录窗口后出现以下问题(login.res_token == ""):

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

一段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()

但是,如果我以另一种方式进行编码(不使用递归),则此操作可以正常工作。 例如:

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()

但是在这里我没有在关闭常规窗口后重新打开登录窗口。

如果我写这样的东西,程序会在关闭常规窗口后崩溃并出现相同的错误:

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()

如何更好地解决这个问题?

逻辑是使用信号通知更改并在逻辑部分更改页面

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_())

登录页面.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()
                }
            }
        }
    }
}

通用页面.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