I stripped down my situation to a simple one: I want to program the GUI in PyQt5, where there is a main QGridLayout whose name is grid, in which there are another grid gridParamter and a QListView widget.
In the gridParamter, there are 2 QLabel
Here is the code
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def window():
app = QApplication(sys.argv)
win = QWidget()
list1 = QListView()
gridParameter = QGridLayout()
idxRow = 0
label_1 = QLabel("I am label one")
gridParameter.addWidget(label_1, idxRow, 0)
idxRow = 1
label_2 = QLabel("I am label two")
gridParameter.addWidget(label_2, idxRow, 1)
grid = QGridLayout()
grid.addLayout(gridParameter, 0, 0)
grid.setSpacing(2)
grid.addWidget(list1)
win.setLayout(grid)
win.show()
sys.exit(app.exec_())
if __name__ == '__main__':
window()
which can produce the GUI as I expected. But when I try to rewrite it in OOP style, i.e.
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
list1 = QListView(self)
gridParameter = QGridLayout(self)
idxRow = 0
label_1 = QLabel("I am label one", self)
gridParameter.addWidget(label_1, idxRow, 0)
idxRow = 1
label_2 = QLabel("I am label two", self)
gridParameter.addWidget(label_2, idxRow, 1)
grid = QGridLayout(self)
grid.addLayout(gridParameter, 0, 0)
grid.setSpacing(2)
grid.addWidget(list1)
self.setLayout(grid)
if __name__ == "__main__":
app = QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit( app.exec_() )
I found that the label_1 overlaps with list1, and when I try to resize the main windows, list1 always takes the grid position (0, 0).
First you must understand the following:
Keep in mind that the following expression:
lay = FooLayout()
some_widget.setWidget(lay)
is equivalent to:
lay = FooLayout(some_widget)
And that both indicate that the layout will handle the geometry of the children.
On the other hand, if a widget already has a layout, no other layout can be established unless the previous layout is deleted.
So in your case only the first instruction works and not the next 2 so the layout grid will be eliminated and the listview is only maintained because it is a child of the widget.
gridParameter = QGridLayout(self)
# ...
grid = QGridLayout(self)
# ...
self.setLayout(grid)
In my case I avoid placing the parents of the widgets to see if there is a problem and also I only establish as a parent of the layout if necessary:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
list1 = QtWidgets.QListView()
gridParameter = QtWidgets.QGridLayout()
idxRow = 0
label_1 = QtWidgets.QLabel("I am label one")
gridParameter.addWidget(label_1, idxRow, 0)
idxRow = 1
label_2 = QtWidgets.QLabel("I am label two")
gridParameter.addWidget(label_2, idxRow, 1)
grid = QtWidgets.QGridLayout(self) # <--- principal layout
grid.addLayout(gridParameter, 0, 0)
grid.setSpacing(2)
grid.addWidget(list1)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
mainWin = MainWindow()
mainWin.show()
sys.exit(app.exec_())
In conclusion use self when necessary.
Related
I need to align center some labels that are inside of a QGroupBox ( I want that labels to be centered even on resizing), I tried many "solutions" but none of them worked, the QGroupBox is inside of a QGridLayout and has expanding width.
from PyQt5 import QtCore, QtWidgets, QtGui
import sys
class TestWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
layout = QtWidgets.QHBoxLayout()
self.setLayout(layout)
group = QtWidgets.QGroupBox()
layout.addWidget(group)
group_layout = QtWidgets.QHBoxLayout()
group.setLayout(group_layout)
labelContainerWidget = QtWidgets.QWidget()
labelContainer_layout = QtWidgets.QHBoxLayout()
labelContainerWidget.setLayout(labelContainer_layout)
label1 = QtWidgets.QLabel('test1')
label2 = QtWidgets.QLabel('test2')
group_layout.setAlignment(QtCore.Qt.AlignCenter)
group_layout.addWidget(label1)
group_layout.addWidget(label2)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
form = TestWidget()
form.show()
app.exec_()
Use layout.setAlignment(QtCore.Qt.AlignCenter)
I want to create a log in screen. But I cant move these 2 Labels in the mid of the screen. I'm sure you can help me guys :) See pics in the Link.
https://ibb.co/vP1ydvk
https://ibb.co/crWh94n
def show_welcome_message(self):
vertical_layout = QVBoxLayout()
horizontal_layout = QHBoxLayout()
group_box = QGroupBox()
welcome_label = QLabel("Welcome!")
user_label = QLabel("Logged in as test test test")
welcome_label.setFont(QFont("Times", 20))
vertical_layout.addStretch(1)
vertical_layout.addWidget(welcome_label)
vertical_layout.addWidget(user_label)
vertical_layout.addStretch(1)
horizontal_layout.addStretch(1)
horizontal_layout.addLayout(vertical_layout)
horizontal_layout.addStretch(1)
group_box.setLayout(horizontal_layout)
self.MainWindow.setCentralWidget(group_box)
Here is an example of a widget with two centered labels:
from PyQt5 import QtWidgets, QtCore
if __name__ == "__main__":
app = QtWidgets.QApplication([])
label1 = QtWidgets.QLabel('This is a label')
label2 = QtWidgets.QLabel('This is another label')
# center text within labels
label1.setAlignment(QtCore.Qt.AlignCenter)
label2.setAlignment(QtCore.Qt.AlignCenter)
widget = QtWidgets.QWidget()
layout = QtWidgets.QVBoxLayout(widget)
# center labels within layout
layout.setAlignment(QtCore.Qt.AlignCenter)
layout.addWidget(label1)
layout.addWidget(label2)
widget.resize(400,400)
widget.show()
app.exec()
Try it:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
centralWidget = QWidget()
self.setCentralWidget(centralWidget)
grid = QGridLayout(centralWidget)
group_box = QGroupBox()
grid.addWidget(group_box)
self.vertical_layout = QVBoxLayout()
group_box.setLayout(self.vertical_layout)
self.show_welcome_message()
def show_welcome_message(self):
welcome_label = QLabel("Welcome!", alignment=Qt.AlignCenter)
welcome_label.setFont(QFont("Times", 20))
user_label = QLabel("Logged in as test test test", alignment=Qt.AlignCenter)
self.vertical_layout.addStretch(1)
self.vertical_layout.addWidget(welcome_label)
self.vertical_layout.addWidget(user_label)
self.vertical_layout.addStretch(1)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
I'm using the QPushButton to load the UI. First -> Jumin -> Department -> next -> next I want to create the UI in order. The problem is that I can not load the third Department into the QMainwindow window. I do not know why
When you create a widget in QVBoxLayout, it changes the size of the widget according to the wallpaper like wxpython layout (wx.all). Can not change the position (move) and size (resize) by automatic centering?
import sys
from PyQt5.QtWidgets import *
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.center_widget = QWidget()
self.setCentralWidget(self.center_widget)
self.FirstUI()
def FirstUI(self):
self.btn1 = QPushButton('test1', self)
self.btn1.move(50, 50)
self.btn1.clicked.connect(self.btn1_click)
def JuminUI(self):
self.ju1 = QLineEdit('13')
self.btn2 = QPushButton('^^^^^^^^^^')
self.ju_text = QLabel('asd')
self.jumim_layout = QVBoxLayout()
self.jumim_layout.addWidget(self.ju_text)
self.jumim_layout.addWidget(self.ju1)
self.jumim_layout.addWidget(self.btn2)
self.centralWidget().setLayout(self.jumim_layout)
self.btn2.clicked.connect(self.btn2_click)
def DepartmentUI(self):
self.depart_layout = QVBoxLayout()
self.depart_layout.addWidget(QPushButton('sdfsdf'))
self.centralWidget().setLayout(self.depart_layout)
def btn1_click(self):
self.btn1.deleteLater()
self.JuminUI()
def btn2_click(self):
self.ju1.deleteLater()
self.btn2.deleteLater()
self.ju_text.deleteLater()
self.DepartmentUI()
if __name__ == "__main__":
app = QApplication(sys.argv)
fream = MainWindow()
fream.show()
app.exec_()
creating and removing widgets is almost always a bad idea, and your code falls into those bad ideas, it's always best to hide the widgets and for that you should use the QStackedWidget, what QStackedWidget does is just make a widget visible on all widgets that you have been assigned by changing the currentIndex.
import sys
from functools import partial
from PyQt5 import QtWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.center_widget = QtWidgets.QStackedWidget()
self.setCentralWidget(self.center_widget)
self.FirstUI()
self.JuminUI()
self.DepartmentUI()
def FirstUI(self):
widget = QtWidgets.QWidget()
self.btn1 = QtWidgets.QPushButton('test1', widget)
self.btn1.move(50, 50)
self.center_widget.addWidget(widget)
self.btn1.clicked.connect(partial(self.center_widget.setCurrentIndex, 1))
def JuminUI(self):
widget = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(widget)
self.ju1 = QtWidgets.QLineEdit('13')
self.btn2 = QtWidgets.QPushButton('^^^^^^^^^^')
self.ju_text = QtWidgets.QLabel('asd')
lay.addWidget(self.ju_text)
lay.addWidget(self.ju1)
lay.addWidget(self.btn2)
self.center_widget.addWidget(widget)
self.btn2.clicked.connect(partial(self.center_widget.setCurrentIndex, 2))
def DepartmentUI(self):
widget = QtWidgets.QWidget()
lay = QtWidgets.QVBoxLayout(widget)
lay.addWidget(QtWidgets.QPushButton('sdfsdf'))
self.center_widget.addWidget(widget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
fream = MainWindow()
fream.show()
sys.exit(app.exec_())
Here's my code. I'm trying to make it such that as you change the dropdown box, it will dynamically show more or less QLineEdits for input. This is just the latest iteration of testing
import sys
from PyQt5.QtWidgets import (QWidget, QPushButton, QLineEdit,
QInputDialog, QApplication, QComboBox, QFrame)
import numpy as np
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
#
# Set up GUI
#
self.setGeometry(100, 100, 400, 400)
self.move(300, 300)
combobox = QComboBox(self)
for i in range(1, 10, 1):
combobox.addItem(str(i + 1))
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
frame = QWidget(self)
frame.hide()
for num in range(0, int(text), 1):
QLineEdit(frame).move(60, num * 19)
frame.show()
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())
The problem is that when you pass a parent to a widget it is placed in the 0, 0 position with respect to the parent, in your case QFrame is on top of QComboBox since both are in the 0, 0 position. The proper thing is to use layouts. On the other hand you have to eliminate the widgets before adding new ones for it, we create a function that eliminates those items.
import sys
from PyQt5.QtWidgets import *
def clearLayout(lay):
while lay.count() > 0:
item = lay.takeAt(0)
widget = item.widget()
if widget:
widget.deleteLater()
del item
class GUI(QWidget):
def __init__(self):
super().__init__()
self.initgui()
def initgui(self):
lay = QHBoxLayout(self)
vlay1 = QVBoxLayout()
combobox = QComboBox(self)
combobox.addItems([str(i) for i in range(2, 11)])
vlay1.addWidget(combobox)
vlay1.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
self.vlay2 = QVBoxLayout()
lay.addLayout(vlay1)
lay.addLayout(self.vlay2)
self.comboboxchanged(combobox.currentText())
combobox.activated[str].connect(self.comboboxchanged)
self.setWindowTitle("Testing Easy Setup")
self.show()
def comboboxchanged(self, text):
clearLayout(self.vlay2)
for num in range(0, int(text)):
self.vlay2.addWidget(QLineEdit(self))
self.vlay2.addItem(QSpacerItem(20, 245, QSizePolicy.Minimum, QSizePolicy.Expanding))
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = GUI()
sys.exit(app.exec_())
I'm trying to make two scroll bars for a QGroupBox but I only succeed having one (the vertical one)
I'm not sure what I need to do.
here is a short example of my code:
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.centralTabs= QTabWidget()
self.setCentralWidget(self.centralTabs)
self.setFixedWidth(200)
self.setFixedHeight(200)
#tab Model selection
self.tab_ModelSelect = QWidget()
self.centralTabs.addTab(self.tab_ModelSelect,"Label")
self.groupscrolllayouttest = QHBoxLayout()
self.groupscrollbartest = QGroupBox()
self.mainHBOX_param_scene = QVBoxLayout()
for i in range(10):
Label = QLabel('BlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla')
Label.setFixedWidth(200)
self.mainHBOX_param_scene.addWidget(Label)
#
scroll = QScrollArea()
scroll.setWidget(self.groupscrollbartest)
scroll.setWidgetResizable(True)
scroll.setFixedWidth(20)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.groupscrollbartest.setLayout(self.mainHBOX_param_scene)
self.groupscrolllayouttest.addWidget(self.groupscrollbartest)
self.groupscrolllayouttest.addWidget(scroll)
self.tab_ModelSelect.setLayout(self.groupscrolllayouttest)
def main():
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
# ex.showMaximized()
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
and here is the result:
In my more complex code I used QTabWidget, that why I included it in this example. What I would like to do is having a horizontal scrollbar to the bottom which allows me to shift the text left and right. Obviously I want keep the other one to shift the text up and down.
I also try to add a second scroll bar to the first one (groupscrolllayouttest)
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import sys
class SurfViewer(QMainWindow):
def __init__(self, parent=None):
super(SurfViewer, self).__init__()
self.parent = parent
self.centralTabs= QTabWidget()
self.setCentralWidget(self.centralTabs)
self.setFixedWidth(200)
self.setFixedHeight(200)
#tab Model selection
self.tab_ModelSelect = QWidget()
self.centralTabs.addTab(self.tab_ModelSelect,"Label")
self.groupscrolllayouttest2 = QVBoxLayout() ####
self.groupscrollbartest2 = QGroupBox() ####
self.groupscrolllayouttest = QHBoxLayout() ####
self.groupscrollbartest = QGroupBox() ####
self.mainHBOX_param_scene = QVBoxLayout()
for i in range(10):
Label = QLabel('BlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBlaBla')
Label.setFixedWidth(200)
self.mainHBOX_param_scene.addWidget(Label)
#
scroll = QScrollArea()
scroll.setWidget(self.groupscrollbartest)
scroll.setWidgetResizable(True)
scroll.setFixedWidth(20)
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
# self.mainHBOX_param_scene.addWidget(scroll)
self.groupscrollbartest.setLayout(self.mainHBOX_param_scene)
self.groupscrolllayouttest.addWidget(self.groupscrollbartest)
self.groupscrolllayouttest.addWidget(scroll)
scroll2 = QScrollArea()
scroll2.setWidget(self.groupscrollbartest2)
scroll2.setWidgetResizable(True)
scroll2.setFixedWidth(20)
scroll2.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
scroll2.setHorizontalScrollBarPolicy(Qt.ScrollBarAsNeeded)
self.groupscrollbartest2.setLayout(self.groupscrolllayouttest)
self.groupscrolllayouttest2.addWidget(self.groupscrollbartest2)
self.groupscrolllayouttest2.addWidget(scroll2)
self.tab_ModelSelect.setLayout(self.groupscrolllayouttest2)
def main():
app = QApplication(sys.argv)
ex = SurfViewer(app)
ex.setWindowTitle('window')
# ex.showMaximized()
ex.show()
sys.exit(app.exec_( ))
if __name__ == '__main__':
main()
But I end up with a strange scroll bar:
So now I'm stuck. Any idea?
What you have to do is create a widget, and in that widget place the QGroupBox:
[...]
scroll = QScrollArea()
widget = QWidget(self)
widget.setLayout(QVBoxLayout())
widget.layout().addWidget(self.groupscrollbartest)
scroll.setWidget(widget)
scroll.setWidgetResizable(True)
self.groupscrollbartest.setLayout(self.mainHBOX_param_scene)
self.groupscrolllayouttest.addWidget(scroll)
self.tab_ModelSelect.setLayout(self.groupscrolllayouttest)
[...]
Output: