1) I'm trying to create an app using PyQt5. When a login is succesfull I get to the select page created using the class Ui_select. This works fine. However when I try to logout using the back arrow for some reason the page crashes even though if I run the gui_select.py file first as if it's the main file the back arrow works without issue.
2) I created the Windows using Qt Designer but I'm trying to edit them to work without using the check if the file is main==> if name == "main": above app = QtWidgets.QApplication(sys.argv) since I only want the code creating the login window to be the main file.
*This is the code for the login page:
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_())
*This is the code for the option select page:
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_())
Thanks in advance
If you run your code on a shell/prompt, you'll see the following error:
Exception "unhandled NameError"
name 'select' is not defined
File: /tmp/gui_select.py, Line: 14
This is because select
is only declared within the if __name__
of the second file.
__main__
When a python file is loaded, everything in its main indentation level is processed, even when the script is imported.
In your case, what's within the __name__
check in the second file is not executed (because for that file, __name__
is actually gui_select
), which means that that whole block will be ignored and select
will not be created, hence the crash with the above error.
The if __name__
check is not only good practice, but also often mandatory.
If you move everything in that block outside the if
, it will be executed as soon as you import the file from the main script; the result would be that when you launch the first script, it will import the second, which will be completely executed, so it will create the QApplication instance and the select window, and then immediately show it without going further until that window is closed; then it will just exit the program (due to the sys.exit
call) without showing the login window at all.
This is highly discouraged, as it often results in a moltitude of problems and misunderstandings (like in this case), but also the main reason is that whenever you need to modify again the GUI for any reason, you'll get serious troubles merging your existing code with the new files created by pyuic. As shown in the official guidelines about using Designer (and partially suggested by the "WARNING" in those files), those scripts must never be manually modified and should always be used as imports.
This are the steps you need to follow:
.ui
files with pyuic (ensure that the object name of the second window is select
in Designer);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_())
Some considerations:
image = QtGui.QPixmap('path_to_image.png').scaled(width, height, transformMode=QtCore.Qt.SmoothTransformation)
;iconSize()
property, so it's not clear why you want to scale the image to 1920x1920; if you want to specify a bigger size, use self.back_button.setIconSize(QtCore.QSize(width, height))
;lambda
;time.sleep(1)
in the first file) should never be called in the main Qt thread, as they prevent not only interaction, but most importantly correct GUI update/drawing: in fact, you will probably see that the button text is not updated with the "wrong password" text; use a QMessageBox instead, or a QTimer connected to a slot that updates the label: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)
self.window
or self.ui
, as it may lead to confusion: those attributes should refer to the window and ui of the current class instance, if they belong to another instance you should probably name them with something like self.otherWindow
and self.otherUi
; this is not a programmatical issue, but a code reading/reviewing one: using well chosen names improves reading and understanding, which is very important even if it's your own code;