Python qt: layouts
This page contains QLayout
subclasses, and container widgets.
General Info
Useful Methods
layout = QtWidgets.QVBoxLayout() layout.setAlignment( QtCore.Qt.AlignTop ) # pin objects to the top of layout layout.setSpacing(0) # space between all controls in a layout layout.setContentsMargins(0,0, 0,0) # marginSize inside layout before controls drawn ## QLayouts do not have a way to set a maximum size for themselves ## **but** QWidgets do. You can set a maximum layout size by adding ## the layout to a QWidget widget = QtGui.QWidget() widget.setLayout(hbox) widget.setMaximumSize(0, 100) layout.addLayout(layout) # Nest Layout (from parent) layout.addWidget(button) # Add Widget to Layout layout.addItem(spacer) # Add Spacer item to Layout layout.indexOf(spacer) # get the index of an item in a layoutObject Stretchiness
Controls have default size-policies. For instance, buttons stretch horizontally (not vertically) even if their parent layout should make them do otherwise. You can override their sizePolicy with setSizePolicy.
Note
In the documentation, note that setSizePolicy is a member of the QtGui.QWidget class. Remember that this library is object-oriented, and QPusButtons are in the inheritance heirarchy as QtGui.QWidget.QPushButton. This means that they will inherit all the methods/attributes that belong to QtGui.QWidget.
btn = { 'a':'', 'b':'', 'c':'' } for ctrl in btn: ctrl = QtGui.QPushButton( ctrl ) ctrl.setSizePolicy( QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding) vbox.addWidget( ctrl ) win.setLayout(vbox) win.show()Space Between Objects
branchVertLayout.setSpacing(0) branchVertLayout.setContentsMargins(0,0, 0,0)Attach Controls to Form Edge
h = QtGui.QHBoxLayout() h.addStretch(1) ## All objects will be pushed all the way to the end of the layout
Layouts
QHBoxLayout/QVBoxLayout
## THIS NEEDS FURTHER DOCUMENTATION AND EXPERIMENTATION ## I DO NOT FULLY UNDERSTAND HOW LAYOUTS ACTUALLY WORK... ## ## Create Buttons okButton = QtGui.QPushButton("OK") cancelButton = QtGui.QPushButton("Cancel") ## Layouts hbox = QtGui.QHBoxLayout() # Create Horizonal BoxLayout hbox.addStretch(1) # Push edge of layout all the way to it's maximum (right) hbox.addWidget(okButton) # Add items to Layout hbox.addWidget(cancelButton) vbox = QtGui.QVBoxLayout() # Create Vertical BoxLayout vbox.addStretch(1) # Push edge of vertical layout to it's maximum (bottom) vbox.addLayout(hbox) # Add horizontal boxLayout # Combination of both means layout hbox items are at bottomRight self.setLayout(vbox) # Attach 'vbox' layout to the window (so grows/shrinks with it)GridLayout
Gridlayouts are interesting, and different than they are treated in MEL. You attach objects to specific positions in the grid, then adjust the space between the elements.
#### Simple GridLayout ## Array of ButtonNames names = ['Cls' , 'Bck' , '' , 'Close' , '7' , '8' , '9' , '/' , '4' , '5' , '6' , '*' , '1' , '2' , '3' , '-' , '0' , '.' , '=' , '+' ] ## Build GridLayout grid = QtGui.QGridLayout() j = 0 pos = [ (0, 0), (0, 1), (0, 2), (0, 3), # This Array is unecessary, gridLayouts (1, 0), (1, 1), (1, 2), (1, 3), # seem to automatically adjust to the (2, 0), (2, 1), (2, 2), (2, 3), # largest index an item is assigned to (3, 0), (3, 1), (3, 2), (3, 3), (4, 0), (4, 1), (4, 2), (4, 3) ] ## Assign a button per-gridLayout-position for i in names: button = QtGui.QPushButton(i) if j == 2: grid.addWidget( QtGui.QLabel(''), 0, 2 ) else: grid.addWidget( button, pos[j][0], pos[j][1] ) # GridLayouts work a little differently here j=j + 1 # you seem to attach controls to a position # rather than their left/right side... ## Attach a (primary) layout to the window (i think...) self.setLayout(grid)#### More Complicated Layout ## Create GUI Objects title = QtGui.QLabel('Title' ) ## Left Column GUI Objects author = QtGui.QLabel('Author') review = QtGui.QLabel('Review') titleEdit = QtGui.QLineEdit() ## Right Column GUI Objects authorEdit = QtGui.QLineEdit() reviewEdit = QtGui.QTextEdit() ## Create GridLayout grid = QtGui.QGridLayout() grid.setSpacing(90) ## Space between GUI elements in grid. # Can also adjust vertically/horizontally # separately ( setHorizontalSpacing ) ## Add Objects to Layout grid.addWidget( title ,1 ,0 ) ## ( object, y,x ) Note that like curses, these are y/x grid.addWidget( titleEdit ,1 ,1 ) grid.addWidget( author ,2 ,0 ) grid.addWidget( authorEdit ,2 ,1 ) grid.setRowMinimumHeight( 3, 50 ) ## Create an emtpy 'spacer' column in a gridLayout. # (you can also use this to set a minimum height for a column with items) grid.addWidget( review ,4 ,0 ) grid.addWidget( reviewEdit ,4 ,1 ,5 ,1 )
Container Widgets
These aren't actually layouts, but their sole purpose is to contain other widgets. The above information about layouts does not apply to these widgets.
QSplitter (drag-resize)
QSplitters let you create a layout that is resizeable by mouse.
NOTE:
The most effective place to use QSplitter()setStretchFactor is immediately after you add widgets to it. It does not seem to take effect if used too early, or too late.
WARNING:
A Vanilla QT Application will not draw anything to represen a splitter (no 3 dots, mayastyle). You can create global presets for this using CSS.
#### Create Horizontal QSplitter #### splitH = QtGui.QSplitter( QtCore.Qt.Orientation( QtCore.Qt.Horizontal ) ) for i in xrange(0, 3): # Add 3 Objects to QSplitter splitH.addWidget( QtGui.QPushButton( str(i)) ) splitH.setStretchFactor( 1, 50 ) # Make QPushButton at index[1]'s split occupy 50% # of window's room by default mainV.addWidget( splitH ) # Assign Parent Layout#### Add Layouts to QSplitter #### logVSP = QtGui.QSplitter( QtCore.Qt.Orientation( QtCore.Qt.Vertical ) ) log = QtGui.QWidget() # Create a QWidget to contain layouts logV = QtGui.QVBoxLayout() # Add Layout logT = Title() # Add Title logT.new( label='test', parent=logV ) logCont = QtGui.QTextEdit() # Add TextEdit logV.addWidget( logCont ) log.setLayout( logV ) # Set QWidget layout logVSP.addWidget( log ) # Add QWidget to QSplitterQScrollArea
WARNING:
A QScrollArea's widget's layout does not behave the same when setting alignment on it. (ex: QVBoxLayout().setAlignment( QtCore.Qt.AlignTop ). You can work around this by nesting another layout/widget/layout combo underneath that layout. The childmost widget will handle alignment as you originally expected.
## build widgets main_layout = QtGui.QVBoxLayout() scroll = QtGui.QScrollArea() layout = QtGui.QVBoxLayout() layout_widget = QtGui.QWidget() ## widget properties scroll.setWidgetResizable(1) # allows widget to change size (ex: if adding several widgets to a layout inside widget) layout.setAlignment(QtCore.Qt.AlignTop) # align all widgets inside scrollArea to top ## populate layout main_layout.addItem(scroll) scroll.setWidget(layout_widget) layout_widget.setLayout(layout)