簡體   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