在 Python 中使用 PyQt5 创建后退按钮
Posted
技术标签:
【中文标题】在 Python 中使用 PyQt5 创建后退按钮【英文标题】:Creating a back button using PyQt5 in Python 【发布时间】:2020-10-12 17:12:34 【问题描述】:1) 我正在尝试使用 PyQt5 创建一个应用程序。当登录成功时,我会进入使用类 Ui_select 创建的选择页面。这工作正常。但是,当我出于某种原因尝试使用后退箭头注销时,即使我首先运行 gui_select.py 文件,就好像它是主文件一样,后退箭头也可以正常工作。
2) 我使用 Qt Designer 创建了 Windows,但我试图编辑它们以使其正常工作,而不使用检查文件是否为 main==> if name == "main": 上面 app = QtWidgets.QApplication(sys.argv) 因为我只希望创建登录窗口的代码是主文件。
*这是登录页面的代码:
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_())
*这是选项选择页面的代码:
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_())
提前致谢
【问题讨论】:
【参考方案1】:如果您在 shell/prompt 上运行代码,您将看到以下错误:
Exception "unhandled NameError"
name 'select' is not defined
File: /tmp/gui_select.py, Line: 14
这是因为select
仅在第二个文件的if __name__
中声明。
存在的重要性__main__
加载 python 文件时,会处理其主缩进级别中的所有内容,即使在导入脚本时也是如此。
在您的情况下,第二个文件中的__name__
检查中的内容未 执行(因为对于那个 文件,__name__
实际上是gui_select
),这意味着整个块将被忽略,select
将不会被创建,因此会出现上述错误的崩溃。
if __name__
检查不仅是一种很好的做法,而且通常是强制性的。
如果您将该块中的所有内容移出if
,它将在您从主脚本导入文件后立即执行;结果将是,当您启动第一个脚本时,它将导入第二个脚本,该脚本将完全执行,因此它将创建 QApplication 实例和选择窗口,然后立即显示它而无需进一步操作,直到该窗口关闭为止; 然后它只会退出程序(由于sys.exit
调用)而不显示登录窗口。
强烈不鼓励这样做,因为它通常会导致大量问题和误解(就像在这种情况下),但主要原因是每当您需要再次修改 GUI 时原因,将现有代码与 pyuic 创建的新文件合并会遇到严重的麻烦。正如关于using Designer 的官方指南所示(以及这些文件中的“警告”部分建议),这些脚本必须永远手动修改,并且应该始终使用作为进口。
这是您需要遵循的步骤:
创建一个新脚本,最终复制您为类添加的函数,这样它们就不会被删除,您可以修改它们而无需从头开始编写它们; 用pyuic再次生成.ui
文件(确保第二个窗口的对象名在Designer中是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 上看到的与运行程序时在屏幕上看到的不完全一样,而且用户在他们的屏幕上看到的也很少;此外,如果用户(或操作系统)调整窗口大小,部分 UI 将变得不可用;请改用layout managers;
阻塞函数(如第一个文件中的time.sleep(1)
)应该永远在主Qt线程中调用,因为它们不仅阻止交互,而且最重要的是阻止正确的GUI更新/绘图:事实上,您可能会看到按钮文本没有更新为“密码错误”文本;改用 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)
虽然建议的修改不再是真正的问题,但您不应将其他窗口/ui 命名为 self.window
或 self.ui
,因为这可能会导致混淆:这些属性应引用窗口和 ui对于当前类实例,如果它们属于另一个实例,您可能应该将它们命名为 self.otherWindow
和 self.otherUi
;这不是程序问题,而是代码阅读/审查问题:使用精心挑选的名称可以提高阅读和理解能力,即使是您自己的代码,这一点也非常重要;
【讨论】:
以上是关于在 Python 中使用 PyQt5 创建后退按钮的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Python、PyQt5 和 Pyinstaller 修复未正确显示的按钮
如何在 python 中使用 pyqt5 显示 2 个按钮和 2 个标签?
如何在 PyQt5 GUI python 中单击按钮时绘制方形图