我正在研究基于qml的应用程序。
环境:
我想要以下行为:
现在在关闭没有访问令牌(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()
如何更好地解决此问题?
答案 0 :(得分:0)
逻辑是使用信号通知更改,并在逻辑部分中更改页面
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()
}