在 Python 中使用 PyQt5 创建后退按钮
Creating a back button using PyQt5 in Python
1) 我正在尝试使用 PyQt5 创建一个应用程序。登录成功后,我会进入使用 class Ui_select 创建的 select 页面。这很好用。但是,当我出于某种原因尝试使用后退箭头注销时,即使我先 运行 gui_select.py 文件,页面也会崩溃,就好像它是主文件一样,后退箭头可以正常工作。
2) 我使用 Qt Designer 创建了 Windows 但我试图编辑它们以在不检查文件是否为 main 的情况下工作 ==> if name == "main": 以上 app = QtWidgets.QApplication(sys.argv) 因为我只希望创建登录 window 的代码成为主文件。
*这是登录页面的代码:
from PyQt5 import QtCore, QtGui, QtWidgets
import gui_select
import time, getpass
number = 2
users = {'m': 1} #Test the dictionary tommorow to see if it will work accordingly
class Ui_MainWindow(object):
def openWindow(self, user_id, password):
x = users.get(user_id)
if x == int(password): # Figure out how to make the dictionary work
MainWindow.close()
self.window = QtWidgets.QMainWindow()
self.ui = gui_select.Ui_select()
self.ui.setupUi(self.window)
self.window.show()
else:
self.login.setText("Wrong Password, Please Retry")
time.sleep(1)
self.login.setText("Login")
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1099, 775)
MainWindow.setStyleSheet("background-color: rgb(4, 112, 54)\n"
"")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(490, 10, 111, 41))
font = QtGui.QFont()
font.setFamily("Broadway")
font.setPointSize(35)
self.label_2.setFont(font)
self.label_2.setStyleSheet("color: rgb(255, 255, 255)")
self.label_2.setObjectName("label_2")
self.groupBox_login_info = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_login_info.setGeometry(QtCore.QRect(390, 517, 274, 171))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(14)
self.groupBox_login_info.setFont(font)
self.groupBox_login_info.setStyleSheet("color: rgb(255, 255, 255)")
self.groupBox_login_info.setObjectName("groupBox_login_info")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox_login_info)
self.horizontalLayout.setObjectName("horizontalLayout")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.lineEdit_password = QtWidgets.QLineEdit(self.groupBox_login_info)
self.lineEdit_password.setStyleSheet("color: rgb(255, 255, 255)")
self.lineEdit_password.setEchoMode(QtWidgets.QLineEdit.Password)
self.lineEdit_password.setObjectName("lineEdit_password")
self.gridLayout.addWidget(self.lineEdit_password, 1, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
font.setBold(True)
font.setWeight(75)
self.label_3.setFont(font)
self.label_3.setStyleSheet("color: rgb(255, 255, 255)")
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
self.label = QtWidgets.QLabel(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
font.setBold(True)
font.setWeight(75)
self.label.setFont(font)
self.label.setStyleSheet("color: rgb(255, 255, 255)")
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lineEdit_user_id = QtWidgets.QLineEdit(self.groupBox_login_info)
self.lineEdit_user_id.setStyleSheet("color: rgb(255, 255, 255)")
self.lineEdit_user_id.setObjectName("lineEdit_user_id")
self.gridLayout.addWidget(self.lineEdit_user_id, 0, 1, 1, 1)
self.login = QtWidgets.QPushButton(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(14)
self.login.setFont(font)
self.login.setObjectName("login")
self.login.clicked.connect(lambda: self.openWindow(self.lineEdit_user_id.text(), self.lineEdit_password.text()))
self.gridLayout.addWidget(self.login, 2, 0, 1, 2)
self.horizontalLayout.addLayout(self.gridLayout)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(130, 60, 791, 451))
self.label_4.setMaximumSize(QtCore.QSize(791, 471))
self.label_4.setText("")
self.label_4.setPixmap(QtGui.QPixmap("Resource File\Landing page image.png"))
self.label_4.setObjectName("label_4")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1099, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_2.setText(_translate("MainWindow", "Blu"))
self.groupBox_login_info.setTitle(_translate("MainWindow", "Login info:"))
self.label_3.setText(_translate("MainWindow", "Password:"))
self.label.setText(_translate("MainWindow", "User ID:"))
self.login.setText(_translate("MainWindow", "Login"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
*这是选项 select 页面的代码:
from PyQt5 import QtCore, QtGui, QtWidgets
import gui_login
import os
from PIL import Image
number = 2
this_dir = os.path.abspath(os.path.dirname(__file__))
some_image = os.path.join(this_dir, 'Resource File', 'Back_arrow_image.png')
class Ui_select(object):
def openWindow(self):
select.close()
self.window = QtWidgets.QMainWindow()
self.ui = gui_login.Ui_MainWindow()
self.ui.setupUi(self.window)
self.window.show()
def back_arrow(self):
self.back_button = QtWidgets.QPushButton(self.centralwidget)
self.back_button.setGeometry(QtCore.QRect(770, 30, 221, 81))
self.back_button.setObjectName("back_button")
BlackArrow = Image.open(some_image)
new_image = BlackArrow.resize((1920, 1920))
new_image.save("WhiteArrow.png")
self.back_button.setIcon(QtGui.QIcon("WhiteArrow.png"))
self.back_button.clicked.connect(lambda: self.openWindow())
def setupUi(self, select):
select.setObjectName("select")
select.resize(1090, 600)
select.setStyleSheet("background-color: rgb(4, 112, 54)\n"
"")
self.centralwidget = QtWidgets.QWidget(select)
self.centralwidget.setObjectName("centralwidget")
self.set_parameters = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters.setGeometry(QtCore.QRect(380, 300, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters.setFont(font)
self.set_parameters.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters.setObjectName("set_parameters")
self.set_parameters_2 = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters_2.setGeometry(QtCore.QRect(380, 390, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters_2.setFont(font)
self.set_parameters_2.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters_2.setObjectName("set_parameters_2")
self.set_parameters_3 = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters_3.setGeometry(QtCore.QRect(380, 210, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters_3.setFont(font)
self.set_parameters_3.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters_3.setObjectName("set_parameters_3")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(470, 60, 111, 41))
font = QtGui.QFont()
font.setFamily("Broadway")
font.setPointSize(35)
self.label_2.setFont(font)
self.label_2.setStyleSheet("color: rgb(255, 255, 255)")
self.label_2.setObjectName("label_2")
select.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(select)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 26))
self.menubar.setObjectName("menubar")
self.menuMenu = QtWidgets.QMenu(self.menubar)
self.menuMenu.setObjectName("menuMenu")
select.setMenuBar(self.menubar)
self.back_arrow()
self.statusbar = QtWidgets.QStatusBar(select)
self.statusbar.setObjectName("statusbar")
select.setStatusBar(self.statusbar)
self.menubar.addAction(self.menuMenu.menuAction())
self.retranslateUi(select)
QtCore.QMetaObject.connectSlotsByName(select)
def retranslateUi(self, select):
_translate = QtCore.QCoreApplication.translate
select.setWindowTitle(_translate("select", "MainWindow"))
self.set_parameters.setText(_translate("select", "Set Parameters"))
self.set_parameters_2.setText(_translate("select", "History"))
self.set_parameters_3.setText(_translate("select", "Auto Detect"))
self.label_2.setText(_translate("select", "Blu"))
self.menuMenu.setTitle(_translate("select", "Menu "))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
select = QtWidgets.QMainWindow()
ui = Ui_select()
ui.setupUi(select)
select.show()
sys.exit(app.exec_())
提前致谢
如果您 运行 您的代码在 shell/prompt 上,您将看到以下错误:
Exception "unhandled NameError"
name 'select' is not defined
File: /tmp/gui_select.py, Line: 14
这是因为 select
仅在第二个文件的 if __name__
中声明。
存在的重要性__main__
当加载 python 文件时,其主缩进级别中的所有内容 都会被处理,即使在导入脚本时也是如此。
在您的情况下,第二个文件中 __name__
检查中的内容是 not 执行的(因为对于 that 文件,__name__
实际上是 gui_select
),这意味着整个块将被忽略并且不会创建 select
,因此崩溃并出现上述错误。
if __name__
检查不仅是好的做法,而且通常是强制性的。
如果将该块中的所有内容移动到 外部 if
,它将在您从主脚本导入文件后立即执行;结果将是,当您启动第一个脚本时,它将导入第二个脚本,该脚本将被完全执行,因此它将创建 QApplication 实例和 select window,然后立即显示它而不用更进一步,直到 window 关闭; 然后 它将退出程序(由于 sys.exit
调用),根本不显示登录 window。
现在,虽然理论上可以轻松避免该问题,但您的情况存在更大的问题:您修改了 pyuic 生成的文件以创建您的程序。
这是非常气馁的,因为它经常会导致大量的问题和误解(就像在这种情况下),但主要原因是每当你需要修改出于任何原因再次使用 GUI,将现有代码与 pyuic 创建的新文件合并时会遇到严重的麻烦。如官方 guidelines about using Designer 所示(这些文件中的“WARNING”部分建议),这些脚本必须 never 手动修改和应该总是 用作导入。
这是您需要遵循的步骤:
- 创建一个新脚本,最终复制您为 classes 添加的函数,这样它们就不会被删除,您可以修改它们而无需从头开始编写;
- 用pyuic再次生成
.ui
文件(确保第二个window的对象名是select
在设计器中);
- 用这样的东西修改新脚本:
from PyQt5 import QtWidgets
from gui_login import Ui_MainWindow
from gui_select import Ui_select
class LoginWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.login.clicked.connect(self.showSelect)
def showSelect(self):
user_id = self.lineEdit_user_id.text()
password = self.lineEdit_password.text()
x = users.get(user_id)
if x == int(password):
self.close()
self.selectWindow = SelectWindow()
self.selectWindow.show()
else:
# this is *wrong*, see below
self.login.setText("Wrong Password, Please Retry")
time.sleep(1)
self.login.setText("Login")
class SelectWindow(QtWidgets.QMainWindow, Ui_select):
def __init__(self):
super().__init__()
self.setupUi(self)
self.back_button.clicked.connect(self.showLogin)
def showLogin(self):
self.close()
self.loginWindow = LoginWindow()
self.loginWindow.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
loginWindow = LoginWindow()
loginWindow.show()
sys.exit(app.exec_())
一些注意事项:
- Qt已经提供了图片缩放功能,你不需要使用PIL(另外,你不应该每次都保存一张新图片);如果您需要缩放图像,请使用
image = QtGui.QPixmap('path_to_image.png').scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
;
- QPushButton自动根据其
iconSize()
属性缩放图标,所以不清楚为什么要将图片缩放到1920x1920;如果要指定更大的尺寸,请使用 self.back_button.setIconSize(QtCore.QSize(width, height))
;
- 如果您不需要为连接到信号的函数提供自定义参数,请不要使用
lambda
;
- 固定几何形状通常被认为是不好的做法,原因有很多:您在 Designer 上看到的与您在 运行 程序时在屏幕上看到的并不完全相同,而且用户很少会看到在他们身上;此外,如果用户(或 OS)调整 window 的大小,UI 的部分内容将变得不可用;使用 layout managers 代替;
- 阻塞函数(如第一个文件中的
time.sleep(1)
)应该永远不会在主Qt线程中调用,因为它们不仅阻止交互,而且最重要的是正确GUI update/drawing:事实上,您可能会看到按钮文本 而不是 更新为“密码错误”文本;改为使用 QMessageBox,或连接到更新标签的插槽的 QTimer:
class LoginWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# ...
def showSelect(self):
# ...
else:
self.login.setText("Wrong Password, Please Retry")
self.login.setEnabled(False)
QtCore.QTimer.singleShot(2000, self.restoreLogin)
def restoreLogin(self):
self.login.setText("Login")
self.login.setEnabled(True)
- 虽然根据建议的修改,这不再是真正的问题,但您不应将另一个 window/ui 命名为
self.window
或 self.ui
,因为这可能会导致混淆:那些属性应引用当前 class 实例的 window 和 ui,如果它们属于另一个实例,您可能应该用 self.otherWindow
和 [=33= 之类的名称命名它们];这不是程序问题,而是代码问题 reading/reviewing:使用精心选择的名称可以提高阅读和理解能力,这非常重要,即使是您自己的代码;
1) 我正在尝试使用 PyQt5 创建一个应用程序。登录成功后,我会进入使用 class Ui_select 创建的 select 页面。这很好用。但是,当我出于某种原因尝试使用后退箭头注销时,即使我先 运行 gui_select.py 文件,页面也会崩溃,就好像它是主文件一样,后退箭头可以正常工作。
2) 我使用 Qt Designer 创建了 Windows 但我试图编辑它们以在不检查文件是否为 main 的情况下工作 ==> if name == "main": 以上 app = QtWidgets.QApplication(sys.argv) 因为我只希望创建登录 window 的代码成为主文件。
*这是登录页面的代码:
from PyQt5 import QtCore, QtGui, QtWidgets
import gui_select
import time, getpass
number = 2
users = {'m': 1} #Test the dictionary tommorow to see if it will work accordingly
class Ui_MainWindow(object):
def openWindow(self, user_id, password):
x = users.get(user_id)
if x == int(password): # Figure out how to make the dictionary work
MainWindow.close()
self.window = QtWidgets.QMainWindow()
self.ui = gui_select.Ui_select()
self.ui.setupUi(self.window)
self.window.show()
else:
self.login.setText("Wrong Password, Please Retry")
time.sleep(1)
self.login.setText("Login")
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1099, 775)
MainWindow.setStyleSheet("background-color: rgb(4, 112, 54)\n"
"")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(490, 10, 111, 41))
font = QtGui.QFont()
font.setFamily("Broadway")
font.setPointSize(35)
self.label_2.setFont(font)
self.label_2.setStyleSheet("color: rgb(255, 255, 255)")
self.label_2.setObjectName("label_2")
self.groupBox_login_info = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox_login_info.setGeometry(QtCore.QRect(390, 517, 274, 171))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(14)
self.groupBox_login_info.setFont(font)
self.groupBox_login_info.setStyleSheet("color: rgb(255, 255, 255)")
self.groupBox_login_info.setObjectName("groupBox_login_info")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.groupBox_login_info)
self.horizontalLayout.setObjectName("horizontalLayout")
self.gridLayout = QtWidgets.QGridLayout()
self.gridLayout.setObjectName("gridLayout")
self.lineEdit_password = QtWidgets.QLineEdit(self.groupBox_login_info)
self.lineEdit_password.setStyleSheet("color: rgb(255, 255, 255)")
self.lineEdit_password.setEchoMode(QtWidgets.QLineEdit.Password)
self.lineEdit_password.setObjectName("lineEdit_password")
self.gridLayout.addWidget(self.lineEdit_password, 1, 1, 1, 1)
self.label_3 = QtWidgets.QLabel(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
font.setBold(True)
font.setWeight(75)
self.label_3.setFont(font)
self.label_3.setStyleSheet("color: rgb(255, 255, 255)")
self.label_3.setObjectName("label_3")
self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1)
self.label = QtWidgets.QLabel(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
font.setBold(True)
font.setWeight(75)
self.label.setFont(font)
self.label.setStyleSheet("color: rgb(255, 255, 255)")
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lineEdit_user_id = QtWidgets.QLineEdit(self.groupBox_login_info)
self.lineEdit_user_id.setStyleSheet("color: rgb(255, 255, 255)")
self.lineEdit_user_id.setObjectName("lineEdit_user_id")
self.gridLayout.addWidget(self.lineEdit_user_id, 0, 1, 1, 1)
self.login = QtWidgets.QPushButton(self.groupBox_login_info)
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(14)
self.login.setFont(font)
self.login.setObjectName("login")
self.login.clicked.connect(lambda: self.openWindow(self.lineEdit_user_id.text(), self.lineEdit_password.text()))
self.gridLayout.addWidget(self.login, 2, 0, 1, 2)
self.horizontalLayout.addLayout(self.gridLayout)
self.label_4 = QtWidgets.QLabel(self.centralwidget)
self.label_4.setGeometry(QtCore.QRect(130, 60, 791, 451))
self.label_4.setMaximumSize(QtCore.QSize(791, 471))
self.label_4.setText("")
self.label_4.setPixmap(QtGui.QPixmap("Resource File\Landing page image.png"))
self.label_4.setObjectName("label_4")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1099, 26))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label_2.setText(_translate("MainWindow", "Blu"))
self.groupBox_login_info.setTitle(_translate("MainWindow", "Login info:"))
self.label_3.setText(_translate("MainWindow", "Password:"))
self.label.setText(_translate("MainWindow", "User ID:"))
self.login.setText(_translate("MainWindow", "Login"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
*这是选项 select 页面的代码:
from PyQt5 import QtCore, QtGui, QtWidgets
import gui_login
import os
from PIL import Image
number = 2
this_dir = os.path.abspath(os.path.dirname(__file__))
some_image = os.path.join(this_dir, 'Resource File', 'Back_arrow_image.png')
class Ui_select(object):
def openWindow(self):
select.close()
self.window = QtWidgets.QMainWindow()
self.ui = gui_login.Ui_MainWindow()
self.ui.setupUi(self.window)
self.window.show()
def back_arrow(self):
self.back_button = QtWidgets.QPushButton(self.centralwidget)
self.back_button.setGeometry(QtCore.QRect(770, 30, 221, 81))
self.back_button.setObjectName("back_button")
BlackArrow = Image.open(some_image)
new_image = BlackArrow.resize((1920, 1920))
new_image.save("WhiteArrow.png")
self.back_button.setIcon(QtGui.QIcon("WhiteArrow.png"))
self.back_button.clicked.connect(lambda: self.openWindow())
def setupUi(self, select):
select.setObjectName("select")
select.resize(1090, 600)
select.setStyleSheet("background-color: rgb(4, 112, 54)\n"
"")
self.centralwidget = QtWidgets.QWidget(select)
self.centralwidget.setObjectName("centralwidget")
self.set_parameters = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters.setGeometry(QtCore.QRect(380, 300, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters.setFont(font)
self.set_parameters.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters.setObjectName("set_parameters")
self.set_parameters_2 = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters_2.setGeometry(QtCore.QRect(380, 390, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters_2.setFont(font)
self.set_parameters_2.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters_2.setObjectName("set_parameters_2")
self.set_parameters_3 = QtWidgets.QPushButton(self.centralwidget)
self.set_parameters_3.setGeometry(QtCore.QRect(380, 210, 281, 71))
font = QtGui.QFont()
font.setFamily("Bahnschrift Light Condensed")
font.setPointSize(18)
self.set_parameters_3.setFont(font)
self.set_parameters_3.setStyleSheet("color: rgb(255, 255, 255)")
self.set_parameters_3.setObjectName("set_parameters_3")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(470, 60, 111, 41))
font = QtGui.QFont()
font.setFamily("Broadway")
font.setPointSize(35)
self.label_2.setFont(font)
self.label_2.setStyleSheet("color: rgb(255, 255, 255)")
self.label_2.setObjectName("label_2")
select.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(select)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1090, 26))
self.menubar.setObjectName("menubar")
self.menuMenu = QtWidgets.QMenu(self.menubar)
self.menuMenu.setObjectName("menuMenu")
select.setMenuBar(self.menubar)
self.back_arrow()
self.statusbar = QtWidgets.QStatusBar(select)
self.statusbar.setObjectName("statusbar")
select.setStatusBar(self.statusbar)
self.menubar.addAction(self.menuMenu.menuAction())
self.retranslateUi(select)
QtCore.QMetaObject.connectSlotsByName(select)
def retranslateUi(self, select):
_translate = QtCore.QCoreApplication.translate
select.setWindowTitle(_translate("select", "MainWindow"))
self.set_parameters.setText(_translate("select", "Set Parameters"))
self.set_parameters_2.setText(_translate("select", "History"))
self.set_parameters_3.setText(_translate("select", "Auto Detect"))
self.label_2.setText(_translate("select", "Blu"))
self.menuMenu.setTitle(_translate("select", "Menu "))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
select = QtWidgets.QMainWindow()
ui = Ui_select()
ui.setupUi(select)
select.show()
sys.exit(app.exec_())
提前致谢
如果您 运行 您的代码在 shell/prompt 上,您将看到以下错误:
Exception "unhandled NameError"
name 'select' is not defined
File: /tmp/gui_select.py, Line: 14
这是因为 select
仅在第二个文件的 if __name__
中声明。
存在的重要性__main__
当加载 python 文件时,其主缩进级别中的所有内容 都会被处理,即使在导入脚本时也是如此。
在您的情况下,第二个文件中 __name__
检查中的内容是 not 执行的(因为对于 that 文件,__name__
实际上是 gui_select
),这意味着整个块将被忽略并且不会创建 select
,因此崩溃并出现上述错误。
if __name__
检查不仅是好的做法,而且通常是强制性的。
如果将该块中的所有内容移动到 外部 if
,它将在您从主脚本导入文件后立即执行;结果将是,当您启动第一个脚本时,它将导入第二个脚本,该脚本将被完全执行,因此它将创建 QApplication 实例和 select window,然后立即显示它而不用更进一步,直到 window 关闭; 然后 它将退出程序(由于 sys.exit
调用),根本不显示登录 window。
现在,虽然理论上可以轻松避免该问题,但您的情况存在更大的问题:您修改了 pyuic 生成的文件以创建您的程序。
这是非常气馁的,因为它经常会导致大量的问题和误解(就像在这种情况下),但主要原因是每当你需要修改出于任何原因再次使用 GUI,将现有代码与 pyuic 创建的新文件合并时会遇到严重的麻烦。如官方 guidelines about using Designer 所示(这些文件中的“WARNING”部分建议),这些脚本必须 never 手动修改和应该总是 用作导入。
这是您需要遵循的步骤:
- 创建一个新脚本,最终复制您为 classes 添加的函数,这样它们就不会被删除,您可以修改它们而无需从头开始编写;
- 用pyuic再次生成
.ui
文件(确保第二个window的对象名是select
在设计器中); - 用这样的东西修改新脚本:
from PyQt5 import QtWidgets
from gui_login import Ui_MainWindow
from gui_select import Ui_select
class LoginWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.login.clicked.connect(self.showSelect)
def showSelect(self):
user_id = self.lineEdit_user_id.text()
password = self.lineEdit_password.text()
x = users.get(user_id)
if x == int(password):
self.close()
self.selectWindow = SelectWindow()
self.selectWindow.show()
else:
# this is *wrong*, see below
self.login.setText("Wrong Password, Please Retry")
time.sleep(1)
self.login.setText("Login")
class SelectWindow(QtWidgets.QMainWindow, Ui_select):
def __init__(self):
super().__init__()
self.setupUi(self)
self.back_button.clicked.connect(self.showLogin)
def showLogin(self):
self.close()
self.loginWindow = LoginWindow()
self.loginWindow.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
loginWindow = LoginWindow()
loginWindow.show()
sys.exit(app.exec_())
一些注意事项:
- Qt已经提供了图片缩放功能,你不需要使用PIL(另外,你不应该每次都保存一张新图片);如果您需要缩放图像,请使用
image = QtGui.QPixmap('path_to_image.png').scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
; - QPushButton自动根据其
iconSize()
属性缩放图标,所以不清楚为什么要将图片缩放到1920x1920;如果要指定更大的尺寸,请使用self.back_button.setIconSize(QtCore.QSize(width, height))
; - 如果您不需要为连接到信号的函数提供自定义参数,请不要使用
lambda
; - 固定几何形状通常被认为是不好的做法,原因有很多:您在 Designer 上看到的与您在 运行 程序时在屏幕上看到的并不完全相同,而且用户很少会看到在他们身上;此外,如果用户(或 OS)调整 window 的大小,UI 的部分内容将变得不可用;使用 layout managers 代替;
- 阻塞函数(如第一个文件中的
time.sleep(1)
)应该永远不会在主Qt线程中调用,因为它们不仅阻止交互,而且最重要的是正确GUI update/drawing:事实上,您可能会看到按钮文本 而不是 更新为“密码错误”文本;改为使用 QMessageBox,或连接到更新标签的插槽的 QTimer:
class LoginWindow(QtWidgets.QMainWindow, Ui_MainWindow):
# ...
def showSelect(self):
# ...
else:
self.login.setText("Wrong Password, Please Retry")
self.login.setEnabled(False)
QtCore.QTimer.singleShot(2000, self.restoreLogin)
def restoreLogin(self):
self.login.setText("Login")
self.login.setEnabled(True)
- 虽然根据建议的修改,这不再是真正的问题,但您不应将另一个 window/ui 命名为
self.window
或self.ui
,因为这可能会导致混淆:那些属性应引用当前 class 实例的 window 和 ui,如果它们属于另一个实例,您可能应该用self.otherWindow
和 [=33= 之类的名称命名它们];这不是程序问题,而是代码问题 reading/reviewing:使用精心选择的名称可以提高阅读和理解能力,这非常重要,即使是您自己的代码;