[Qt] Layout affecting non-associated children

63 views
Skip to first unread message

Marcus Ottosson

unread,
Jan 3, 2014, 7:33:18 AM1/3/14
to python_in...@googlegroups.com
This little caveat has been bothering me for a few hours.

Adding a widget as a child of a parent widget makes it position itself at (0, 0). That's fine, I can move it around in resizeEvent. The size of the widget is determined by its children - say if the widget is a container for a couple of buttons, the amount of buttons and their default sizes govern the size of the container.

But, installing a layout onto the parent of the container causes the container to seemingly force its children to resize to an inappropriate size.

I could imaging that assigning a layout to a parent with children might implicitly assign its children to the layout, but that isn't what I would expect. Ultimately, I would like to have a completely free-floating widget.

Uncomment the layout line to see what happens. This happens in both PyQt4 and 5 so I expect to be missing something trivial.


from PyQt4.QtGui import *
from PyQt4.QtCore import *




class Window(QWidget):
   
def __init__(self, parent=None):
       
super(Window, self).__init__(parent)


        menu
= QWidget(self)
        menu
.setObjectName('Menu')


        btn1
= QPushButton('Hello')
        btn2
= QPushButton('World')


        layout
= QBoxLayout(QBoxLayout.LeftToRight, menu)
        layout
.addWidget(btn1)
        layout
.addWidget(btn2)


       
# layout = QBoxLayout(QBoxLayout.TopToBottom, self)


       
self.setStyleSheet("#Menu {background-color: darkgray; }")
       
self.resize(300, 100)


       
if __name__ == '__main__':
   
import sys
    app
= QApplication(sys.argv)


    win
= Window()
    win
.show()


    sys
.exit(app.exec_())

Joe Weidenbach

unread,
Jan 3, 2014, 12:19:54 PM1/3/14
to python_in...@googlegroups.com
From my understanding, once you're using a layout, the layout handles sizing on all of your contained objects, and resize() doesn't do much at all for you.  The trick here is to set your minimumSize() and maximumSize() properties on the buttons, along with a look into QSizePolicy options for both horizontal and vertical, and then the layout will work off of those to handle sizing.  I'll see if I have time later today to give you a few samples in case that doesn't make sense :).
--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/240d1de8-ead1-455a-a344-ff991db44398%40googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Justin Israel

unread,
Jan 3, 2014, 2:51:25 PM1/3/14
to python_in...@googlegroups.com
Joe is right about needing to set some size constraints/policies on your widgets to control their behavior. 

Just to correct one thing though... 
Adding a widget as a child of a parent widget makes it position itself at (0, 0). That's fine, I can move it around in resizeEvent. The size of the widget is determined by its children - say if the widget is a container for a couple of buttons, the amount of buttons and their default sizes govern the size of the container.
The size of the parent widget is not necessarily determined by its children. It *can* be determined by its children if a layout is installed and there are no overruling size contraints being applied to the parent. If you make widgets children of another, without a layout, they are all allowed to overlap and be cropped off by the parent. It is only the layout engine that constantly observes the children to manage the size of the parent. 
But, installing a layout onto the parent of the container causes the container to seemingly force its children to resize to an inappropriate size.

I could imaging that assigning a layout to a parent with children might implicitly assign its children to the layout, but that isn't what I would expect. Ultimately, I would like to have a completely free-floating widget.
I would actually expect it not to mess with the layout assignments of existing children, when adding a layout. There are times when you want both layout constrained children, an floating positioned children. 

Marcus Ottosson

unread,
Jan 4, 2014, 9:13:38 AM1/4/14
to python_in...@googlegroups.com
Thanks for your help, Joe, it makes sense.

However resize() does work, even after assigning a layout to the parent.
menu.resize(500, 100) enlarges the menu enough to fit the buttons.

Altering size policies doesn't seem to have much of an effect here either.



from PyQt4.QtGui import *
from PyQt4.QtCore import *




class Window(QWidget):
   
def __init__(self, parent=None):
       
super(Window, self).__init__(parent)


        menu
= QWidget(self)
        menu
.setObjectName('Menu')

       
# menu.resize(500, 200)



        btn1
= QPushButton('Hello')
        btn2
= QPushButton('World')



       
for wid in (btn1, btn2, menu):
            wid
.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding)



        layout
= QBoxLayout(QBoxLayout.LeftToRight, menu)
        layout
.addWidget(btn1)
        layout
.addWidget(btn2)

        layout
.setSizeConstraint(QLayout.SetNoConstraint)



        layout
= QBoxLayout(QBoxLayout.TopToBottom, self)


       
self.setStyleSheet("#Menu {background-color: darkgray; }")
       
self.resize(300, 100)


       
if __name__ == '__main__':
   
import sys
    app
= QApplication(sys.argv)


    win
= Window()
    win
.show()


    sys
.exit(app.exec_())

To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Marcus Ottosson

unread,
Jan 4, 2014, 9:17:41 AM1/4/14
to python_in...@googlegroups.com

The size of the parent widget is not necessarily determined by its children. It *can* be determined by its children if a layout is installed and there are no overruling size contraints being applied to the parent. If you make widgets children of another, without a layout, they are all allowed to overlap and be cropped off by the parent. It is only the layout engine that constantly observes the children to manage the size of the parent. 

Of course, you are right. I was referring to this example in particular. 

I would actually expect it not to mess with the layout assignments of existing children, when adding a layout. There are times when you want both layout constrained children, an floating positioned children.

As would I, but if you run the code you'll see how it actually does.

Still not sure exactly what is going on.

Justin Israel

unread,
Jan 4, 2014, 4:03:28 PM1/4/14
to python_in...@googlegroups.com
But it is not messing with the layout assignments of existing children that were not previously in the layout. It is just triggered something like an adjustSize operation. Joe was referring to setting min/max constraints on your floating children. Normally you adding and removing layouts from a parent dynamically, which contains floating children not in a layout.

What is your goal here? How do you want your floating menu widget to behave? Is your goal to get it to stick to the top of the main widget, constraining its width to the parent width?



--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Jan 5, 2014, 6:59:02 AM1/5/14
to python_in...@googlegroups.com
Thanks Justin.

Yes, sticking to the top of the parent widget, but that I can manage. I'm more interested in knowing why this behaviour occurs. I found it unexpected.



For more options, visit https://groups.google.com/groups/opt_out.



--
Marcus Ottosson
konstr...@gmail.com

Justin Israel

unread,
Jan 5, 2014, 2:12:33 PM1/5/14
to python_in...@googlegroups.com

Yea probably because of the adjustSize that may get recursively triggered.
If you want to keep it stuck to the width of the parent but have full controll of its position then you could manage it from the parents resizeEvent()

Marcus Ottosson

unread,
Jan 5, 2014, 5:00:04 PM1/5/14
to python_in...@googlegroups.com
Yes, this was the solution that I ended up with. Thanks for your help Justin.



For more options, visit https://groups.google.com/groups/opt_out.



--
Marcus Ottosson
konstr...@gmail.com

Reply all
Reply to author
Forward
0 new messages