I've realized when creating a class variable to hold a QWidget, it crashes complaining that there is no QApplication. I could break it down to do this minimal example.
import sys
from PyQt4 import QtGui, QtCore
class ThumbContextMenu(QtGui.QMenu):
def __init__(self):
super(ThumbContextMenu, self).__init__()
class Example(QtGui.QWidget):
menu = ThumbContextMenu()
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Quit button')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
Commenting #menu will launch the application, or putting #menu as an instance variable won't crash too.
Maybe you want to use delayed initialization? Something like this, maybe:
class Example(QtGui.QWidget):
menu = None
def __init__(self):
...
if Example.menu is None:
Example.menu = ThumbContextMenu()
The problem is that menu is class variable, so it is being initialized when Example definition is evaluated, i.e. before you call QApplication constructor.
Related
I'm trying to connect the clicked event of a QPushButton inside a class (MyButton) to a function inside the same class (print_hello_world) in PyQt5. I'm expecting to print "Hello World" when the user clicks on the button. Can anyone explain why the following code does not work? (i.e. clicking on the button does not print anything)
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
The above code will work if I add button.push_button.clicked.connect(lambda:button) after I instantiate the MyButton object in the Window class. Can anyone explain to me why the first code does not work and the following code works?
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
button.push_button.clicked.connect(lambda:button)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
What is an alternative way to make the first code work by modifying the MyButton class without having to add extra lines of code after instantiating the class?
I am also learning and working on PyQt based software development. I did a few experiments with the code and by calling super initialization, the first code works fine. Here is the modified code:
import sys
from PyQt5.QtWidgets import *
class MyButton(QWidget):
def __init__(self, parent):
super().__init__(parent)
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
'button' is destroyed because of garbage collection inside 'Window's init method, because it is not an instance variable so 'button' goes out of scope when init method finishes.
So this version works as intended:
import sys
from PyQt5.QtWidgets import *
class MyButton:
def __init__(self, parent):
self.parent = parent
self.push_button = QPushButton('Print', parent)
self.push_button.clicked.connect(self.print_hello_world)
def print_hello_world(self):
print("Hello World")
class Window(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.button = MyButton(parent=self)
App = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(App.exec())
So my expected outcome is for the login.ui to show when the login button is clicked. My code reached the def gotologin function and the class LoginScreen , but it doesn't load the ui
import sys
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QDialog, QApplication
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi('welcomescreen.ui', self)
self.login.clicked.connect(self.gotologin)
def gotologin(self):
login = LoginScreen()
widget.addWidget(login)
widget.setCurrentIndex(widget.currentIndex()+1)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi('login.ui', self)
app = QApplication(sys.argv)
welcome = WelcomeScreen()
widget = QtWidgets.QStackedWidget()
widget.addWidget(welcome)
widget.setFixedHeight(800)
widget.setFixedWidth(1200)
window = WelcomeScreen()
window.show()
try:
sys.exit(app.exec_())
except:
print('Exiting')
Your logic is strange since you are creating 2 WelcomeScreen: One added to the QStackedWidget and the second as a window. Besides that, the QStackedWidget has never been shown. And as the icing on the cake you don't limit the scopes of the variables.
Considering the above, it is better to create a controller that implements the logic of switching widgets and limits scopes.
import sys
from functools import cached_property
from PyQt5.uic import loadUi
from PyQt5.QtWidgets import QApplication, QDialog, QStackedWidget
class WelcomeScreen(QDialog):
def __init__(self):
super(WelcomeScreen, self).__init__()
loadUi("welcomescreen.ui", self)
class LoginScreen(QDialog):
def __init__(self):
super(LoginScreen, self).__init__()
loadUi("login.ui", self)
class Controller:
def __init__(self):
self.stacked_widget.addWidget(self.welcome)
self.stacked_widget.addWidget(self.login)
self.welcome.login.clicked.connect(self.goto_login)
#cached_property
def stacked_widget(self):
return QStackedWidget()
#cached_property
def welcome(self):
return WelcomeScreen()
#cached_property
def login(self):
return LoginScreen()
def goto_login(self):
self.stacked_widget.setCurrentWidget(self.login)
def main(args):
app = QApplication(args)
controller = Controller()
controller.stacked_widget.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main(sys.argv)
And finally, do not silence the exceptions since their reason for being is to indicate that something is wrong. I prefer that when the program fails then it shouts at me that a silent error since the latter is the cause of many bugs.
So I have 2 GUIs. One is the main gui which has one push button to activate the second gui. The second gui is a simple calculator which sums two numbers when I push the button with external function.The second gui (the calculator) runs fine standalone However when I try to activate the second gui from the main one the program crashes so I probably doing something wrong.
Also if I change the code in main to this:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.SumCalcBtn.clicked.connect(self.OpenSecondWindow)
def OpenSecondWindow(self):
self.ex = SumCalculator(self)
self.ex.show()
It runs but doesn't do anything in second gui when I push the button to sum the numbers.(it seems the methods didn't pass to the instance)
I attach the code for better understanding:
Main.py
import sys
from calculators import summary
from PyQt5 import QtCore, QtGui, QtWidgets
from SummaryUI import Ui_SummaryUI
from SummaryMain import SumCalc
from MainWindow import Ui_MainWindow
class SumCalculator(SumCalc):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.SumCalcBtn.clicked.connect(self.OpenSecondWindow)
def OpenSecondWindow(self):
self.ex = SumCalc(self)
self.ex.show()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
SummaryMain.py
import sys
from calculators import summary
from PyQt5 import QtCore, QtGui, QtWidgets
from SummaryUI import Ui_SummaryUI
class SumCalc(QtWidgets.QMainWindow, Ui_SummaryUI):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
Ui_SummaryUI.__init__(self)
self.setupUi(self)
self.CalculateSumBtn.clicked.connect(self.sum_function)
def sum_function(self):
number_a = int(self.FirstNumberInput.text())
number_b = int(self.SecondNumberInput.text())
sum = summary(number_a, number_b)
self.SumResultsValue.setText(str(sum))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = SumCalc()
window.show()
sys.exit(app.exec_())
replace self.ex = SumCalc(self) with self.ex = SumCalc() because the constructor(__init__) function of SumCalc does not take any argument (def __init__(self))
or juts add parameter parent to SumCalc's constructor so it becomes def __init__(self, parent=none)
Let's say I have this snippet of code:
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWidgets import QDialog
from PyQt5.QtCore import pyqtSignal
from ui_helloworld import Ui_MainWindow
from ui_hellodialog import Ui_Hi
from sys import argv
from sys import exit
class MainWindow(QMainWindow):
update = pyqtSignal(str)
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label)
self.ui.doIt.clicked.connect(self.h.update_label)
def update_label(self):
self.h.show()
def update_label_hello(self, msg):
self.update.emit(msg)
class HelloDialog(QDialog):
def __init__(self):
super(HelloDialog, self).__init__()
self.ui = Ui_Hi()
self.ui.setupUi(self)
def update_label(self, msg):
print msg
# Crashes the program:
# TypeError: setText(self, str): argument 1 has unexpected type 'bool'
# >> self.ui.label.setText(msg)
self.ui.label.setText("Hello world!")
def main():
app = QApplication(argv)
window = MainWindow()
window.show()
exit(app.exec_())
if __name__=="__main__":
main()
It's fairly simple. It's 2 windows, one is a QMainWindow and the other is a QDialog. The MainWindow has 2 buttons, pushButton and doIt:
pushButton opens the HelloDialog
doIt emit the update signal
The problem is, that the slot in HelloDialog Is receiving a boolean from the update signal in MainWindow, but I declared it as a str object.
Why does the the update_label slot receive a bool and not a str object?
localhost :: Documents/Python/qt ยป python main.py
{ push `doIt` object }
False
The Ui_MainWidow and Ui_Hi classes are pyuic5 generated.
I did not need to connect to self.h.update_label directly. I had to connect to the method inside MainWindow called update_label_hello to doIt, and then connect the pyqtSignal to the slot in HelloDialog
So, the final result is this:
init of MainWindow:
def __init__(self):
super(MainWindow, self).__init__()
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.h = HelloDialog()
self.ui.pushButton.clicked.connect(self.update_label_)
self.ui.doIt.clicked.connect(self.update_label_hello)
self.update.connect(self.h.update_label)
I'm new to PyQt5 and I've got an error (pythonw.exe not working anymore) with the following code:
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(self.q)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Quit button')
self.show()
def q():
print('test')
sys.exit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
app.exec_()
First it works, but only until I push the "quit" button. Then the error message pops up.
If I put the q() function outside the class (and change "self.q" into "q") it works fine.
What's the problem?
Thanks in advance.
Windows 7
Python 3.4.3 (x86)
PyQt 5.5.1 (x86)
that's because when q() is inside the class it's expects a compulsory argument as the first parameter, this is usually called self and is passed for you implicitly by python when you're calling the method (q() not q(self)). just as you've done with the initUI method in your class, when you put it outside the class, it's just a normal function and not a method again (function in a class), so it's fine to define the function without self
import sys
from PyQt5.QtWidgets import QWidget, QPushButton, QApplication
from PyQt5.QtCore import QCoreApplication
class Example(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
qbtn = QPushButton('Quit', self)
qbtn.clicked.connect(self.q)
qbtn.resize(qbtn.sizeHint())
qbtn.move(50, 50)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('Quit button')
self.show()
def q(self):
print('test')
sys.exit()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
app.exec_()