Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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?


  • Lifetime Qt Champion

    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.


  • Lifetime Qt Champion

    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_())
    

  • Lifetime Qt Champion

    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!
    

Log in to reply