簡體   English   中英

在 Python 中使用 PyQt5 創建后退按鈕

[英]Creating a back button using PyQt5 in Python

1)我正在嘗試使用 PyQt5 創建一個應用程序。 當登錄成功時,我會進入使用類 Ui_select 創建的選擇頁面。 這工作正常。 但是,當我出於某種原因嘗試使用后退箭頭注銷時,即使我首先運行 gui_select.py 文件,就好像它是主文件一樣,頁面也會崩潰,后退箭頭沒有問題。

2)我使用 Qt Designer 創建了 Windows,但我試圖編輯它們以使其工作而不使用檢查文件是否為 main==> if name == " main ": above 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_())

提前致謝

如果您在 shell/提示上運行代碼,您將看到以下錯誤:

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調用)而sys.exit不顯示登錄窗口。


現在,雖然理論上可以輕松避免該問題,但在您的情況下存在一個更大的問題:您已經修改了 `pyuic` 生成的文件來創建您的程序。

這是非常不鼓勵的,因為它通常會導致大量的問題和誤解(例如在這種情況下),但主要原因是每當您出於任何原因需要再次修改 GUI 時,您都會遇到嚴重的問題來合並您的pyuic 創建的新文件的現有代碼。 作為對官方指南顯示使用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 將不可用; 改用布局管理器
  • 永遠不應在主 Qt 線程中time.sleep(1)阻塞函數(如第一個文件中的time.sleep(1) ,因為它們不僅會阻止交互,而且最重要的是阻止正確的 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.windowself.ui ,因為這可能會導致混淆:這些屬性應指代當前的窗口和 ui類實例,如果它們屬於另一個實例,您可能應該使用self.otherWindowself.otherUi類的名稱來命名它們; 這不是程序問題,而是代碼閱讀/審查問題:使用精心挑選的名稱可以提高閱讀和理解能力,這非常重要,即使是您自己的代碼;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM