Solved Managing the Size of Layouts and Widgets within them...
-
Hi friends,
I'm working on understanding how to get my application to look the way I want it to with the layouts functionality using PySide2. I have 3 specific questions/issues I'm looking for some help with.
-
Is there a way to make it so that when a selection is made between two radio buttons one of two Widgets appears in the same place (in this case a QLineEdit and a QComboBox widget).
-
Is there a way to control the spacing of widgets other than using padding? With my radio buttons I'm using a horizontal layout within a vertical layout to put them side by side but there are only two of them and I don't like how far apart they are so I'd like to center them within the layout with a fixed padding size between the two widgets. Is that possible?
-
The application I'm building will be run in full screen mode when it's all built. Is there a way to fix the size of a column in a horizontal layout (or a row in a vertical layout) so it always takes up a specific percentage of the total window size. Currently I'm using layouts within layouts to structure the document. For example with the code below if I want VertLay (which is the layout used as the second column in HorizLay) to always be 1/3 of the total screen is there an easy way to do that?
Thanks in advance for any advice you can give me. The code I'm working with is below.
from PySide2.QtCore import Qt from PySide2.QtWidgets import QApplication, QWidget, QVBoxLayout from PySide2.QtWidgets import QLineEdit, QListWidget, QLabel from PySide2.QtWidgets import QRadioButton, QButtonGroup from PySide2.QtWidgets import QComboBox, QHBoxLayout from sys import exit as sysExit class Widget(QWidget): def __init__(self): QWidget.__init__(self) self.radiobutton1 = QRadioButton("New") self.radiobutton2 = QRadioButton("Load") self.label1 = QLabel("Name") self.newvalue = QLineEdit() self.selectvalue = QComboBox() self.datalist = QListWidget() self.radiobuttons = QButtonGroup() self.radiobuttons.addButton(self.radiobutton1) self.radiobuttons.addButton(self.radiobutton2) RadioLay = QHBoxLayout() RadioLay.addWidget(self.radiobutton1) RadioLay.addWidget(self.radiobutton2) VertLay = QVBoxLayout() VertLay.addLayout(RadioLay) VertLay.addWidget(self.label1) VertLay.addWidget(self.newvalue) HorizLay = QHBoxLayout() HorizLay.addWidget(self.datalist) HorizLay.addLayout(VertLay) self.setLayout(HorizLay) if __name__ == "__main__": MainEventHandler = QApplication([]) application = Widget() application.show() sysExit(MainEventHandler.exec_())
-
-
Heya,
Yeah if you don't want the splitter you can just use a layout and set the setStretch factor
https://doc.qt.io/qt-5/qboxlayout.html
Just start two a simple widget with a layout and add two widget to it. Then play with setting the stretch to get a feel for the behavoir.For the radial button I use setMinimumSize(80, 20) for them, you can comment all these out first. Then the QSpacerItem "hor_spacer_center " is a fixed pixel amount to can control between the two radial buttons. Have a play with that to bring them closer together
Cheers,
Edit: expanding example
from PySide2.QtWidgets import QHBoxLayout,QLineEdit, QListWidget,QSizePolicy, QApplication, QWidget from sys import exit as sysExit class Widget(QWidget): def __init__(self): QWidget.__init__(self) self.h_layout = QHBoxLayout() self.view = QListWidget() self.view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.line = QLineEdit() self.line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.h_layout.addWidget(self.view, stretch=3) self.h_layout.addWidget(self.line, stretch=1) self.setLayout(self.h_layout) if __name__ == "__main__": MainEventHandler = QApplication([]) application = Widget() application.show() sysExit(MainEventHandler.exec_())
-
Hi,
Personally I find using Qt Designer and generating a .ui is always easier for me. Other people like to code it. I'll try my best at the ladder :P
-
For this kind of stuff i have just been creating all four widgets at once then hide and unhided then base on signals generated from the buttons. In this case i connected the toggle signal to a custom function to manage the visible attribute.
-
you can crate a horizontal spacer between the radial buttons and set its width to a fixed amount. I don't think I need to add the other two horizontal spacer here. We might be able to set an alignment policy on the layout to center the buttons, but I cant test that atm.
-
I created a splitter and set the stretch factor to 3 time of the data_list_widget, splitters are also nice as the user can move the ui around if there is a long text.
Hope that helps,
If anyone has a clean layout let me know, I am lazy and use .ui all the time :P
from PySide2.QtCore import Qt from PySide2.QtWidgets import QApplication, QWidget from PySide2.QtWidgets import QLineEdit, QListWidget, QLabel, QComboBox, QRadioButton from PySide2.QtWidgets import QSplitter, QSpacerItem, QSizePolicy from PySide2.QtWidgets import QHBoxLayout, QGridLayout, QGroupBox from sys import exit as sysExit class Widget(QWidget): def __init__(self): QWidget.__init__(self) self.left_grid_layout = QGridLayout() self.left_side_properties_grp = QGroupBox('Properties') self.grp_grid_layout = QGridLayout() self.left_side_properties_grp.setLayout(self.grp_grid_layout) self.h_layout = QHBoxLayout() self.new_radio_btn = QRadioButton("New") self.new_radio_btn.setMinimumSize(80, 20) self.new_le = QLineEdit() self.new_le.setMinimumSize(80, 20) self.load_radio_btn = QRadioButton("Load") self.load_radio_btn.setMinimumSize(80, 20) self.load_cbox = QComboBox() self.load_cbox.setMinimumSize(80, 20) self.load_cbox.addItems(['Shmee', 'Shmoo', 'Foo']) self.hor_spacer_l = QSpacerItem(2, 2, QSizePolicy.Expanding, QSizePolicy.Minimum) self.hor_spacer_center = QSpacerItem(30, 2, QSizePolicy.Fixed, QSizePolicy.Fixed) self.hor_spacer_r = QSpacerItem(2, 2, QSizePolicy.Expanding, QSizePolicy.Minimum) self.h_layout.addItem(self.hor_spacer_l) self.h_layout.addWidget(self.new_radio_btn) self.h_layout.addWidget(self.new_le) self.h_layout.addItem(self.hor_spacer_center) self.h_layout.addWidget(self.load_radio_btn) self.h_layout.addWidget(self.load_cbox) self.h_layout.addItem(self.hor_spacer_r) self.name_lb = QLabel("Name") self.name_le = QLineEdit() self.vertical_spacer = QSpacerItem(2, 2, QSizePolicy.Minimum, QSizePolicy.Expanding) self.grp_grid_layout.addLayout(self.h_layout, 0, 0) self.left_grid_layout.setAlignment(self.h_layout, Qt.AlignRight) self.grp_grid_layout.addWidget(self.name_lb) self.grp_grid_layout.addWidget(self.name_le) self.grp_grid_layout.addItem(self.vertical_spacer) self.data_list_widget = QListWidget() self.vert_splitter = QSplitter(Qt.Horizontal) self.vert_splitter.addWidget(self.data_list_widget) self.vert_splitter.addWidget(self.left_side_properties_grp) self.vert_splitter.setStretchFactor(0, 3) self.vert_splitter.setStretchFactor(1, 1) self.left_grid_layout.addWidget(self.vert_splitter) self.setLayout(self.left_grid_layout) self.new_le.setVisible(False) self.load_cbox.setVisible(False) self.new_radio_btn.toggled.connect(lambda: self.manage_buttons(True)) self.load_radio_btn.toggled.connect(lambda: self.manage_buttons(False)) def manage_buttons(self, toggle): self.new_le.setVisible(toggle) self.new_radio_btn.setVisible(not toggle) self.load_cbox.setVisible(not toggle) self.load_radio_btn.setVisible( toggle) if __name__ == "__main__": MainEventHandler = QApplication([]) application = Widget() application.show() sysExit(MainEventHandler.exec_())
-
-
Hey friends thanks for the quick responses. These are really helpful. The toggles work great for displaying only the fields I want to show, and I really like the vertical spacer that alom used but I'm wondering if there's a way to make it so users can't move the spacer to adjust the size of the column.
The one thing that still doesn't seem to be working is centering the radio buttons in their layout area. When the view is stretched the radio buttons are shifted left of center with too much spacing between them:
When the view is more compact the New button is left justified instead of centered and there's still too much space between them.
I don't really want to use a label or anything like that to offset them because that could cause problems as the program is used on computers with different screen sizes. I guess what I'm really looking to understand is what tools do I have with PySides an QT that will allow me to control the placement of widgets within a layout but still allow for responsive design.
-
Heya,
Yeah if you don't want the splitter you can just use a layout and set the setStretch factor
https://doc.qt.io/qt-5/qboxlayout.html
Just start two a simple widget with a layout and add two widget to it. Then play with setting the stretch to get a feel for the behavoir.For the radial button I use setMinimumSize(80, 20) for them, you can comment all these out first. Then the QSpacerItem "hor_spacer_center " is a fixed pixel amount to can control between the two radial buttons. Have a play with that to bring them closer together
Cheers,
Edit: expanding example
from PySide2.QtWidgets import QHBoxLayout,QLineEdit, QListWidget,QSizePolicy, QApplication, QWidget from sys import exit as sysExit class Widget(QWidget): def __init__(self): QWidget.__init__(self) self.h_layout = QHBoxLayout() self.view = QListWidget() self.view.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.line = QLineEdit() self.line.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) self.h_layout.addWidget(self.view, stretch=3) self.h_layout.addWidget(self.line, stretch=1) self.setLayout(self.h_layout) if __name__ == "__main__": MainEventHandler = QApplication([]) application = Widget() application.show() sysExit(MainEventHandler.exec_())