PyQt window created within a class __init__ does not display [duplicate] - pyqt

This question already has answers here:
Understanding Python super() with __init__() methods [duplicate]
(7 answers)
Variable scopes in Python classes
(4 answers)
Closed 2 years ago.
This code from a tutorial works fine in PyQt5 if I call it from __main__
window = QWidget()
layout = QVBoxLayout()
layout.addWidget(QPushButton('Top'))
layout.addWidget(QPushButton('Bottom'))
window.setLayout(layout)
window.show()
If I put the code class in the __init__ of a class:
class MainWindow (QMainWindow):
def __init__ (self):
print ("HERE 1")
window = QWidget()
layout = QVBoxLayout()
layout.addWidget(QPushButton('Top'))
layout.addWidget(QPushButton('Bottom'))
window.setLayout(layout)
window.show()
print ("HERE 2")
return
then in __main__:
app = QApplication (args)
mw = MainWindow.MainWindow ()
return app.exec_ ()
Then the print statemets happen but no widgets display.
Why would window not display in the second case? (The corresponding C++ code would display it.)

You need a bit more code to make this run. You are trying to show the widget window but you are not showing the QmainWindow. If the widget is on the QMainWindow it will be visible when you show the main window. You also need to call init from the QMainWindow class to set everything up. Finally, with a QMainWindow, you need to set a central widget.
I generally take a different approach in main. Take a look at my code below:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout, QPushButton
class MainWindow (QMainWindow):
def __init__ (self):
QMainWindow.__init__(self, parent=None)
print ("HERE 1")
window = QWidget()
layout = QVBoxLayout()
layout.addWidget(QPushButton('Top'))
layout.addWidget(QPushButton('Bottom'))
window.setLayout(layout)
self.setCentralWidget(window)
#window.show()
print ("HERE 2")
return
if __name__=="__main__":
app = QApplication(sys.argv)
mw = MainWindow ()
mw.show()
sys.exit(app.exec_())
If you want to show only the widget not on a QmainWindow, try this:
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget, QVBoxLayout, QPushButton
class MainWindow (QWidget):
def __init__ (self):
QWidget.__init__(self, parent=None)
print ("HERE 1")
layout = QVBoxLayout()
layout.addWidget(QPushButton('Top'))
layout.addWidget(QPushButton('Bottom'))
self.setLayout(layout)
print ("HERE 2")
if __name__=="__main__":
app = QApplication(sys.argv)
mw = MainWindow ()
mw.show()
sys.exit(app.exec_())

Related

Issue in Pyqt with next and previous Pages

so I'm currently working on a little project but I have an issue and all what I've tried did not work. I have 2 files :
Page1test :
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QWidget, QLabel
import sys
from page2test import Page2
class Page1(QWidget):
def __init__(self):
super(Page1, self).__init__()
self.setWindowTitle("Page 1")
label1 = QLabel(self)
label1.setText("\n PAGE 1")
self.btn_inMyApp = QPushButton ('Next page', self)
self.btn_inMyApp.setGeometry(1500,800,275,125)
self.btn_inMyApp.clicked.connect(self.closePage1_OpenPage2)
self.show()
def closePage1_OpenPage2(self):
self.Open = Page2()
self.Open.showMaximized()
self.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Page1()
window.showMaximized()
sys.exit(app.exec_())
And page2test :
from PyQt5.QtWidgets import QPushButton, QWidget, QLabel
from Page1test import Page1
class Page2(QWidget):
def __init__(self):
super(Page2, self).__init__()
self.setWindowTitle("Test window principale")
label1 = QLabel(self)
label1.setText("\n Page2")
self.btn_inMyApp = QPushButton ('previous Page', self)
self.btn_inMyApp.setGeometry(1500,800,275,125)
self.btn_inMyApp.clicked.connect(self.closePage2_OpenPage1)
self.show()
def closePage2_OpenPage1(self):
self.Open = Page1()
self.Open.showMaximized()
self.close()
I run the code of Page1test : empty window with just a Qpushbutton "Next Page", goal : we click on it and it open Page 2 (and close Page 1). And, when we are in Page 2, we have A Qpushbutton with "Previous Page" and when we click on it, it opens page 1, and close Page 2. Like a loop.
But, when I run the code, it returns an error :
cannot import name 'Page2' from partially initialized module 'page2test' (most likely due to a circular import)
and I have no idea how to fix it...
If someone had an idea, it would be really helpful.
So, I've finally found the solution, that was not so difficult in the end. Here it is (if it can help someone) :
Instead of making 2 files, I've done just 1 file. Here is the code :
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QPushButton, QWidget, QLabel, QMainWindow
import sys
class MyApp(QWidget):
def __init__(self):
super(MyApp, self).__init__()
self.setWindowTitle("Page 1")
label1 = QLabel(self)
label1.setText("\n PAGE 1")
self.btn_inMyApp = QPushButton ('Page suivante', self)
self.btn_inMyApp.setGeometry(1500,800,275,125)
self.btn_inMyApp.clicked.connect(self.closePage1_OpenPage2)
self.show()
def btn1_onClicked(self):
pass
def closePage1_OpenPage2(self):
self.Open = NewApp()
self.Open.showMaximized()
self.close()
class NewApp(QMainWindow):
def __init__(self):
super(NewApp, self).__init__()
self.setWindowTitle("Test window principale")
label1 = QLabel(self)
label1.setText("\n Page2")
self.btn_inMyApp = QPushButton ('previous Page', self)
self.btn_inMyApp.setGeometry(1500,800,275,125)
self.btn_inMyApp.clicked.connect(self.closePage2_OpenPage1)
self.show()
def closePage2_OpenPage1(self):
self.Open = MyApp()
self.Open.showMaximized()
self.close()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = MyApp()
window.showMaximized()
sys.exit(app.exec_())
```

PyQt5: QLineEdit doesn't show inside a QGroupBox

I'm creating a PyQt5 application in which I want to put some of QLineEdit widgets inside a QGroupBox.
When I run my application, GroupBox is visible and LineEdit is not.
In CreateLinesEdit() I commented a line which sets the line edit visible, but it opens lineEdit in a new window.
from PyQt5.QtWidgets import QGroupBox, QApplication, QLineEdit, QVBoxLayout, QWidget, QHBoxLayout
import sys
class Window(QWidget):
def __init__(self):
super().__init__()
self.InitWindow()
def InitWindow(self):
self.BoxLayout()
self.AddBox()
self.CreateLinesEdit()
self.show()
def BoxLayout(self):
self.groupBoxScreen = QGroupBox()
self.vbox = QVBoxLayout()
self.vbox_screenGame = QVBoxLayout()
self.hbox_lineEdit = QHBoxLayout()
def AddBox(self):
self.vbox_screenGame.addItem(self.hbox_lineEdit)
self.groupBoxScreen.setLayout(self.vbox_screenGame)
self.vbox.addWidget(self.groupBoxScreen)
self.setLayout(self.vbox)
def CreateLinesEdit(self):
self.lines_edit = []
for i in range(0, 4):
LineEdit = QLineEdit()
# LineEdit.setVisible(True)
self.lines_edit.append(LineEdit)
self.hbox_lineEdit.addWidget(self.lines_edit[i])
if __name__ == "__main__":
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

How can I share data with a pyside2 slot function?

I have a PySide2 GUI application with a QPushButton button with a #Slot function connected to it. How can I share data with the function?
from PySide2.QtCore import Slot
from PySide2.QtWidgets import QApplication, QMainWindow, QWidget, QPushButton, QVBoxLayout
#Slot()
def button_XYZ_callback():
# Function which is executed when the button XYZ is clicked.
# I'd like to access the __main__s context data "parent_data" here.
pass
if __name__ == '__main__':
# parent context data what I want to access (read only)
parent_data = "blub"
application = QApplication(sys.argv)
window = QMainWindow()
central_widget = QWidget()
xyz_button = QPushButton("XYZ", central_widget)
xyz_button.clicked.connect(button_xyz_callback)
layout = QVBoxLayout(central_widget)
layout.addWidget(xyz_button)
window.show()
sys.exit(application.exec_())
Per Python's LEGB rule, the global variable parent_data is accessible from within the button_XYZ_callback function.
If, however, you wish to reduce the function's dependence on global variables, the standard technique is to define a class, and use class or instance attributes to store what was before global values:
# based on code from https://wiki.qt.io/Qt_for_Python_Tutorial_ClickableButton
import sys
from PySide2 import QtCore, QtWidgets, QtGui
class MyWidget(QtWidgets.QWidget):
def __init__(self, data):
QtWidgets.QWidget.__init__(self)
self.data = data
self.button = QtWidgets.QPushButton("Click me!")
self.text = QtWidgets.QLabel("Hello World")
self.text.setAlignment(QtCore.Qt.AlignCenter)
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.text)
self.layout.addWidget(self.button)
self.setLayout(self.layout)
self.button.clicked.connect(self.button_XYZ_callback)
#QtCore.Slot()
def button_XYZ_callback(self):
print(self.data)
if __name__ == "__main__":
parent_data = "blub"
app = QtWidgets.QApplication(sys.argv)
widget = MyWidget(data=parent_data)
widget.show()
sys.exit(app.exec_())
Alternatively, if the data is known before the callback is to be defined, you could use a function factory to place the data in the enclosing scope of the callback:
import sys
from PySide2.QtCore import Slot
from PySide2.QtWidgets import QApplication, QPushButton
def make_callback(data):
#Slot()
def button_XYZ_callback():
print(data)
return button_XYZ_callback
if __name__ == "__main__":
parent_data = "blub"
# https://wiki.qt.io/Qt_for_Python_Tutorial_ClickableButton
app = QApplication(sys.argv)
button = QPushButton("Click me")
button.clicked.connect(make_callback(parent_data))
button.show()
app.exec_()

QMainWindow vs QWidget

I can't find good explanations about the different usage of QMainWindow vs. QWidget in PyQt5 (and Qt in general, I guess). From what I've read, QMainWindow inherits from QWidget, so should be able to do everything QWidget can and more. But when I try to convert an example I've found from QWidget into QMainWindow, the layout gets screwed up.
The example I'm trying to work off is from https://www.tutorialspoint.com/pyqt/pyqt_qstackedwidget.htm. (My GUI will have a StackedWidget as central widget, with a sidepanel for navigation, so getting this example to work in a QMainWidget would be a great basis for my own code.)
PyQT5-converted and slightly shortened version:
#!/usr/bin/env python3
import sys
from PyQt5.QtWidgets import (QApplication, QFormLayout, QLabel, QRadioButton, QCheckBox,
QListWidget, QStackedWidget, QLineEdit,
QHBoxLayout, QGridLayout
)
from PyQt5.Qt import QWidget, QMainWindow
class StackedExample(QMainWindow):
def __init__(self):
super(stackedExample, self).__init__()
self.leftlist = QListWidget ()
self.leftlist.insertItem (0, 'Contact' )
self.leftlist.insertItem (1, 'Personal' )
self.stack1 = QWidget()
self.stack2 = QWidget()
self.stack1UI()
self.stack2UI()
self.Stack = QStackedWidget (self)
self.Stack.addWidget (self.stack1)
self.Stack.addWidget (self.stack2)
grid = QGridLayout()
self.setLayout(grid)
grid.addWidget(self.leftlist,0,0)
grid.addWidget(self.Stack,0,1)
self.leftlist.currentRowChanged.connect(self.display)
self.resize(300,100)
self.show()
def stack1UI(self):
layout = QFormLayout()
layout.addRow("Name",QLineEdit())
layout.addRow("Address",QLineEdit())
self.stack1.setLayout(layout)
def stack2UI(self):
layout = QFormLayout()
sex = QHBoxLayout()
sex.addWidget(QRadioButton("Male"))
sex.addWidget(QRadioButton("Female"))
layout.addRow(QLabel("Sex"),sex)
layout.addRow("Date of Birth",QLineEdit())
self.stack2.setLayout(layout)
def display(self,i):
self.Stack.setCurrentIndex(i)
def main():
app = QApplication(sys.argv)
ex = StackedExample()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
This code worked fine while it was based on QWidget, but when it's based on QMainWidget (like in the above version), everything gets crammed into the upper left corner.
What changes are neccessary to show a layout that works for QWidget in a QMainWindow?
A QMainWindow must have a central widget to display correctly. You need to define a central widget and then add any layouts to it instead of the main window.
class StackedExample(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.leftlist = QListWidget()
self.leftlist.insertItem(0, 'Contact' )
self.leftlist.insertItem(1, 'Personal' )
self.central_widget = QWidget() # define central widget
self.setCentralWidget(self.central_widget) # set QMainWindow.centralWidget
self.stack1 = QWidget()
self.stack2 = QWidget()
self.stack1UI()
self.stack2UI()
self.Stack = QStackedWidget (self)
self.Stack.addWidget (self.stack1)
self.Stack.addWidget (self.stack2)
grid = QGridLayout()
self.centralWidget().setLayout(grid) # add the layout to the central widget
grid.addWidget(self.leftlist,0,0)
grid.addWidget(self.Stack,0,1)
self.leftlist.currentRowChanged.connect(self.display)
self.resize(300,100)
self.show()
There are also other areas besides centralWidget defined for a QMainWindow. Here is the documentation for QMainWindow. It explains this in more detail.

PyQt5 - Add image in background of MainWindow layout

New to PyQt5... Here is a very basic question.
I would like to add an image inside the layout of a widget. This widget is the Main Window / root widget of my application. I use the following code, but I get an error message.
import sys
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setGeometry(300,300,300,220)
self.setWindowTitle("Hello !")
oImage = QImage("backgound.png")
oLayout = QVBoxLayout()
oLayout.addWidget(oImage)
self.setLayout(oLayout)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())
TypeError: QBoxLayout.addWidget(QWidget, int stretch=0, Qt.Alignment alignment=0): argument 1 has unexpected type 'QImage'
Apparently a QLayoutWidget does not accept a QImage as an input. Is there a workaround to have an image appear as a brackground in a QWidget ?
The QVBoxLayout class lines up widgets vertically.
documentation QVBoxLayout
QImage is no widget.
on many widgets e.g. QmainWindow, QLabel you can use
widget.setStyleSheet(„ background-image: url(backgound.png);“)
on my machine this doesn't work with QWidget. In this case you can use the following rewrite of your code:
import sys
from PyQt5.QtCore import QSize
from PyQt5.QtGui import QImage, QPalette, QBrush
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
self.setGeometry(100,100,300,200)
oImage = QImage("test.png")
sImage = oImage.scaled(QSize(300,200)) # resize Image to widgets size
palette = QPalette()
palette.setBrush(QPalette.Window, QBrush(sImage))
self.setPalette(palette)
self.label = QLabel('Test', self) # test, if it's really backgroundimage
self.label.setGeometry(50,50,200,50)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
oMainwindow = MainWindow()
sys.exit(app.exec_())

Resources