因此,我有两个窗口希望能够在它们之间切换,Login和MainWindow,每个窗口都是QWidget
,分别位于其自己的独立文件中,loginUI.py与MainUI.py。
通过创建MainWindow的新实例,我可以在正确的身份验证后轻松地从登录切换到主窗口。但在主窗口中,我希望有一个显示登录屏幕的"断开连接"按钮。
由于两者都在不同的文件中,因此在这种情况下导入会在python中引发循环导入错误。
我尝试过的其他方法有:
-
使用信号并在中间文件中处理它们。这很好,但随着我添加更多的按钮/窗口,文件开始变得有点乱。
-
将Login的实例传递给
MainWindow.__init__(self, login)
,然后只使用self.login.show()
。这似乎是一个好方法,但随着我添加越来越多的窗口,我担心这可能会影响性能,因为有这么多实例只是在后台运行。
这些是正确的方法吗?还是我错过了一个更简单的方法
编辑:
login.py
from PyQt5.QtWidgets import QWidget, QPushButton, QLineEdit
from PyQt5.QtCore import QSize
from mainmenu import MainWindow
from PyQt5 import QtWidgets
import sys
class Login(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setMinimumSize(QSize(300, 200))
self.setWindowTitle("Log in")
self.username = QLineEdit(self)
self.username.move(50, 10)
self.password = QLineEdit(self)
self.password.move(50, 40)
self.connect_button = QPushButton('Connect', self)
self.connect_button.move(50, 100)
self.connect_button.clicked.connect(self.handleConnexion)
def handleConnexion(self):
if self.username.text() == "admin" and self.password.text()=="1":
self.mw = MainWindow()
self.mw.show()
self.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = Login()
mainWin.show()
sys.exit( app.exec_() )
mainmenu.py
from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import QPushButton
from PyQt5.QtWidgets import QMainWindow
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(300, 200))
self.setWindowTitle("Main menu")
disconnect_button = QPushButton('Disconnect', self)
disconnect_button.clicked.connect(self.handeDC)
def handeDC(self):
pass
# here I either send a signal to handle it somewhere else
# or
# if i pass the login instance in __init__, just do login.show()
注意:由于这是一个常见的问题,我将提供一个更广泛的答案,更好地反映对象层次结构
由于";主";顾名思义,该窗口是main窗口,包含该窗口的脚本应该是 main层次结构很重要:你不必考虑窗口的显示顺序,而是考虑它们的相关性。 考虑到这一点,主脚本将: 上面还说明了为什么连续创建新的窗口实例很少是个好主意。 登录窗口也应该是一个QDialog,这使事情变得更容易: 注:exec()
方法是";"阻塞";(对于函数执行,而不是事件循环),并等待对话框被接受或*拒绝。main.py
from PyQt5.QtWidgets import *
from login import Login
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setMinimumSize(300, 200)
self.setWindowTitle('Main menu')
disconnect_button = QPushButton('Disconnect')
self.setCentralWidget(disconnect_button)
# only for a *persistent* login dialog (*see below)
self.login = Login()
disconnect_button.clicked.connect(self.disconnect)
def start(self):
# put here some function that might check for a 'previous' logged in
# state, possibly stored using QSettings.
# in this case, we just assume that the user has never previously
# logged in, so we automatically show the login window; if the above
# function returns True instead, we can safely show the main window
logged = False
if logged:
self.show()
else:
self.showLogin()
def disconnect(self):
self.hide()
self.showLogin()
def showLogin(self):
if self.login.exec():
self.show()
# alternatively (*see below):
login = Login()
if login.exec():
self.show()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.start()
sys.exit(app.exec())
login.py
from PyQt5.QtWidgets import *
class Login(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setMinimumSize(300, 200)
self.setWindowTitle('Log in')
self.username = QLineEdit()
self.password = QLineEdit()
self.password.setEchoMode(self.password.Password)
self.connect_button = QPushButton('Connect', enabled=False)
layout = QGridLayout(self)
layout.addWidget(QLabel('Username:'), 0, 0)
layout.addWidget(self.username, 0, 1)
layout.addWidget(QLabel('Password:'), 1, 0)
layout.addWidget(self.password, 1, 1)
layout.addWidget(self.connect_button, 2, 0, 1, 2)
self.connect_button.clicked.connect(self.handleConnexion)
self.username.textChanged.connect(self.checkFields)
self.password.textChanged.connect(self.checkFields)
def checkFields(self):
if self.username.text() and self.password.text():
self.connect_button.setEnabled(True)
else:
self.connect_button.setEnabled(False)
def handleConnexion(self):
if self.username.text() == 'admin' and self.password.text() == '1':
self.accept()
else:
QMessageBox.warning(self, 'Error',
'Invalid username or password!')
Login
实例,因此用户名和密码字段将"记住";以前的条目;如果您不希望这样,您可以通过重写exec()
来对这些字段调用clear()
(但请记住调用基本实现并返回其结果!);或者,不创建self.login
,而是始终在showLogin()
中创建Login()
的新的本地实例setCentralWidget()
在创建MainWindow
小部件时,您可以隐藏小部件,而不是关闭Login
小部件,这将节省创建新实例的开销,并保持连接的插槽完好无损。
然后,在您的MainWindow
上,您可以创建一个diconnected
信号,当用户单击断开连接按钮时,该信号应该发出。
登录窗口可以监听信号并调用它的show
方法。
我在下面的例子中做了一些更改,并进行了内联评论:
主窗口.py
from PyQt5.QtCore import pyqtSignal # added this
class MainWindow(QMainWindow):
disconnected = pyqtSignal() # added this
def __init__(self):
QMainWindow.__init__(self)
...
disconnect_button = QPushButton('Disconnect', self)
disconnect_button.clicked.connect(self.handeDC)
def handeDC(self):
# ... do some stuff
self.disconnected.emit() # added this
登录.py
class Login(QWidget):
def __init__(self):
QWidget.__init__(self)
...
def handleConnexion(self):
if self.username.text() == "admin" and self.password.text()=="1":
self.mw = MainWindow()
self.mw.disconnected.connect(self.show) # added this
self.mw.show()
self.hide() # changed this
...