Is there a way to set size hints?
-
I have a composite widget consisting of a prefix label, suffix label, and some kind of control between the two. I would like to place several of these widgets in a vertical layout box and have the parts line up. Ideally I would like to set the size hints so all the prefixes had the same hint, all the suffixes the same hint, and all the controls the same hint.
Is there any way to do that?
-
Hi and welcome to devnet,
One way is to have a function that you call to insert the labels in the layout.
Another one is to subclass the layout and add methods to it to add these labels that will set the properties to suitable values.
-
I am using a grid layout. I am able to make things work with dastardly doings.
mport sys from PySide2.QtWidgets import QGridLayout, QLabel, QApplication, QWidget, QLineEdit, QPushButton from PySide2.QtCore import Qt class Labeled_LineEdit(QWidget): """Three labels""" def __init__(self, label, text): super().__init__() self.prefix = QLabel(label) self.edit = QLineEdit() self.edit.setText(text) self.grid = QGridLayout(self) self.grid.addWidget(self.prefix, 0, 0) self.grid.addWidget(self.edit, 0, 1) self.grid.setColumnStretch(0, 0) self.grid.setColumnStretch(1, 1) def same_as(self, pattern): """Make my layout like pattern""" self.prefix.sizeHint = pattern.prefix.sizeHint self.edit.sizeHint = pattern.edit.sizeHint class MyPanel(QWidget): def __init__(self): """Demo my layout problem""" super().__init__() self.a = Labeled_LineEdit('Longer label', 'A') self.b = Labeled_LineEdit('Short', 'B') self.b.same_as(self.a) self.grid = QGridLayout(self) self.grid.addWidget(self.a, 0, 0) self.grid.addWidget(self.b, 1, 0) app = QApplication(sys.argv) main = MyPanel() main.show() sys.exit(app.exec_())
This quite literally copies the size hints from one widget and applies them to another, but I know there has to be a better way.
Are you are suggesting that I subclass the grid layout used here so when it asks for widget size hints I can provide the hints that I want? I like that idea.
-
Sorry, I misunderstood what you were meaning by size hints with layouts.
Looks like you want something a bit like QFormLayout ?
In any case, if you want all your widgets to have the same size, then at some point you'll have have one that serves as reference and then resize the others to match.
Here what you do in Python is nasty in the sense that you replace all the widgets sizeHint methods with the one from the "pattern".
-
Nothing conveys information as well as code.
I don't think I can use QFormLayout. My example is oversimplified and the actual widgets I am trying to align are a bit more complicated. For example, I have a widget with QLineEdit and a slider, min and max labels for the slider tic marks, a prefix and a suffix label. The slider extends from the left of the prefix widget to the right of the QLineEdit. I also have a radio button cluster which has a lot of parts to align.
I do not like monkeypatching the sizeHint methods. That kind of thing will eventually lead to trouble. But I thought this would give you a good idea of what I am trying to achieve. Now I just need a better way of doing it.
I've been looking at the grid layout and am not seeing where I could override the "get sizeHint" behavior. Any hints?
-
How do I tell the layout to update? I think the update() method call in the same_as method is telling the grid in the parent window to update. I want to update the grid layout in the Labeled_Control widget.
I modified the sizeHint monkey patch to be less horrible and this works well most of the time. Occasionally see a problem where one of the widgets is off by a couple of pixels after I call same_as(). If I do something to force the grid layout to update (like set the label text) then all the widgets align.
import sys from functools import partial from PySide2.QtWidgets import QGridLayout, QLabel, QApplication, QWidget, QLineEdit, QPushButton from PySide2.QtCore import Qt class Labeled_Control(QWidget): """Three labels""" def __init__(self, label, text): super().__init__() self.size_ref = None self.parts = [None, None] self._partSizeHint = [None, None] self.prefix = QLabel(label) self.control = QLineEdit() self.control.setText(text) self.grid = QGridLayout(self) self.grid.addWidget(self.prefix, 0, 0) self.grid.addWidget(self.control, 0, 1) self.grid.setColumnStretch(0, 0) self.grid.setColumnStretch(1, 1) @property def prefix(self): return self.parts[0] @prefix.setter def prefix(self, widget): self.set_part(0, widget) @property def control(self): return self.parts[1] @control.setter def control(self, widget): self.set_part(1, widget) def set_part(self, index, widget): """Set part[index] = widget""" part = self.parts[index] if part: # Restore part's sizeHint method part.sizeHint = self._partSizeHint[index] self._partSizeHint[index] = None self.parts[index] = widget if widget: # Override widget's sizeHint method self._partSizeHint[index] = widget.sizeHint widget.sizeHint = partial(self.partSizeHint, index) def partSizeHint(self, index): """Return size hint for part[index]""" if self.size_ref: return self.size_ref.partSizeHint(index) return self._partSizeHint[index]() def same_as(self, pattern): """Make my layout like pattern""" self.size_ref = pattern self.grid.update() class MyPanel(QWidget): def __init__(self): """Demo my layout problem""" super().__init__() self.a = Labeled_Control('Longer label', 'A') self.b = Labeled_Control('Short', 'B') self.b.same_as(self.a) self.grid = QGridLayout(self) self.grid.addWidget(self.a, 0, 0) self.grid.addWidget(self.b, 1, 0) self.b.same_as(self.a) app = QApplication(sys.argv) main = MyPanel() main.show() sys.exit(app.exec_())
-
You might want to consider using a QHBoxLayout and play with the stretch factor to give more or less space to your widgets.
For QFormLayout, I was rather suggesting to take a look St its implementation as a source of idea for yours.
-
I have reasons for using a grid that are not shown in this simple example. Widgets can be aligned vertically or horizontally. Some Labeled_Controls have more than 1 row of widgets. The flexibility of the grid layout makes this easier. I tried using combinations of horizontal and vertical box layouts. That turned out more complicated and the results were not good.
I will investigate using setColumnWidth for the grid layout.
I really wish I could find a way to tell the grid layout to update . This works but I cannot stand it.
def same_as(self, pattern): """Make my layout like pattern""" self.size_ref = pattern self.prefix.setText(self.prefix.text()) # Yuck!