【问题标题】:How to reopen window after closing other one?关闭另一个窗口后如何重新打开窗口?
【发布时间】:2020-03-19 22:34:13
【问题描述】:

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

环境:

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

我希望有以下行为:

  • 最初,会显示登录窗口。
  • 获取访问令牌后,登录页面关闭并显示常规 窗口打开。
  • 关闭常规窗口后,登录窗口再次打开。
  • 关闭登录窗口后(字面意思是,如果我在关闭登录窗口后没有访问令牌)我的程序完成。

现在我在关闭没有访问令牌的登录窗口后遇到以下问题 (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()

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

【问题讨论】:

  • 有一部分让我感到困惑,你说:关闭登录窗口后(字面意思是,如果我在关闭登录窗口后没有访问令牌)我的程序完成了。 i>,如果你还有令牌怎么办?
  • @eyllanesc,当我创建一个新对象 Login() 时,它的属性 self.res_login 最初等于“”。该属性只有在授权后,同时登录窗口关闭时才会改变。
  • mmmm,在我看来,您的所有解决方案都使用结构编程,而不是重新考虑使用 OOP 来使用相同的对象。据我了解,只有拥有令牌才能进入“通用窗口”,没有令牌就不会进入,如果进入“通用窗口”后关闭它,令牌就会被删除,我说的对吗?
  • @eyllanesc ,是的,你是。如果在进入“常规窗口”后我将其关闭,则令牌将被删除,“登录窗口”将再次打开以允许其他用户登录。

标签: python python-3.x pyqt qml pyqt5


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    • 2021-07-09
    相关资源
    最近更新 更多