Reputation: 3710
I try to get a GUI application to work but unfortunately the spacing of the single canvas objects is not as expected. I want to have the following layout:
For the Grid Layout I use the following code:
# Adapt Widget StyleSheet
self.button_classification.setStyleSheet("font: bold 10pt Consolas; color: #009682") # #009682 is the KIT-Green
self.button_start.setStyleSheet('font: bold 10pt Consolas; color: #009682; border-style: outset; border-width: 2px; border-radius: 10px; border-color: #646873; padding: 6px')
self.layout4_image_widget.setStyleSheet('background-image: url(Python_logo.png);')
# Define Layouts
self.window = QWidget()
self.layout = QGridLayout()
# Add Widgets to layouts
self.layout.addWidget(self.canvas_left, 0, 0, 5, 5)
self.layout.addWidget(self.canvas_right, 0, 5, 5, 5)
self.layout.addWidget(self.canvas_right_buttom, 8, 7, 3, 3)
self.layout.addWidget(self.canvas_right_top, 5, 7, 3, 3)
self.layout.addWidget(self.canvas_middle_buttom, 8, 3, 3, 4)
self.layout.addWidget(self.canvas_middle_top, 5, 3, 3, 4)
self.layout.addWidget(self.layout4_image_widget, 5, 0, 3, 3)
self.layout.addWidget(self.button_start, 8, 0, 1, 3)
self.layout.addWidget(self.button_classification, 9, 0, 1, 3)
self.layout.addWidget(self.LCD_Number, 10, 0, 1, 3)
self.window.setLayout(self.layout)
But unfortunately what I receive as result is:
So the rows in the middle 5-7 are to wide.
Upvotes: 0
Views: 1223
Reputation: 48231
Using column and row spans for widgets doesn't work as you seem to believe. Each "cell" in a grid layout might have different sizes, and it all depends on each widget sizeHint and sizePolicy
.
All widget have a default size policy, which is a property that a widget uses to tell its container how it behaves when it is resized (should it expand, have a fixed height/width, can it shrink, etc).
By default, buttons and checkboxes have a fixed vertical policy, which means that they can never grow or shrink.
Every layout has a stretch value that can be assigned for each of its "slots". The stretch always defaults to 0, which leaves to each widget the possibility to grow or shrink to fit its needs, but when that value is set the available spaces are computed by the sum of each stretch in the layout and then divided equally. For example, if you have a simple layout with 2 widgets and a stretch=1 for the first and 2 for the second, the available space will be divided by 3 (1 + 2), with the first occupying a third of it and the second 2 thirds.
For grid layouts you can then use setRowStretch()
and setColumnStretch()
to achieve something like you proposed, but this would work only for widget that have compatible policies (preferred or expanding), and since in your case those buttons have fixed height it wouldn't be enough.
There are two possibilities, but in both cases I'll use a simpler layout, since there's no need to use a high count of rows and columns for the reasons explained above and setRowStretch
/setColumnStretch
can be used instead.
The layout uses just 4 columns:
+----+---+---+----+
| | |
+----+---+---+----+
| | | |
+----+---+---+----+
| | | |
+----+---+---+----+
The first row has two "cells" with a 2 column span, and the following rows have the 2 central slots united as a single cell with a similar span.
In this case there are actually 5 rows, the first has a rowStretch=5, the second 3, and the remaining 1. By manually setting the vertical size policy to the widgets, they can grow to the height required by the stretch of the row they are occupying.
# first row, notice the spans
self.layout.addWidget(self.canvas_left, 0, 0, 1, 2)
self.layout.addWidget(self.canvas_right, 0, 2, 1, 2)
# second row, if the span is not specified defaults to (1, 1)
self.layout.addWidget(self.layout4_image_widget, 1, 0)
self.layout.addWidget(self.canvas_middle_top, 1, 1, 1, 2)
self.layout.addWidget(self.canvas_right_top, 1, 3)
# left widgets for third, fourth and fifth rows
self.layout.addWidget(self.button_start, 2, 0)
self.layout.addWidget(self.button_classification, 3, 0)
self.layout.addWidget(self.LCD_Number, 4, 0)
# remaining widgets, notice the vertical and horizontal spans
self.layout.addWidget(self.canvas_right_buttom, 2, 1, 3, 2)
self.layout.addWidget(self.canvas_middle_buttom, 2, 3, 3, 1)
# the column stretches set based on the grid given by you
self.layout.setColumnStretch(0, 3)
self.layout.setColumnStretch(1, 2)
self.layout.setColumnStretch(2, 2)
self.layout.setColumnStretch(3, 3)
# the row stretches, with the final 3 rows set to 1
self.layout.setRowStretch(0, 5)
self.layout.setRowStretch(1, 3)
self.layout.setRowStretch(2, 1)
self.layout.setRowStretch(3, 1)
self.layout.setRowStretch(4, 1)
# the default policy for both buttons and checkboxes is QSizePolicy.Minimum
# horizontally, and QSizePolicy.Fixed vertically, let's just change the latter
self.button_start.setSizePolicy(
QSizePolicy.Minimum, QSizePolicy.Preferred)
self.button_classification.setSizePolicy(
QSizePolicy.Minimum, QSizePolicy.Preferred)
Unfortunately this isn't perfect: as you can see the button might become too big and the checkbox has a lot of unnecessary margins that could be used by the LCD widget instead.
In this case there only 3 rows, and an extra QWidget is used as container for the widgets on the bottom left.
self.layout.addWidget(self.canvas_left, 0, 0, 1, 2)
self.layout.addWidget(self.canvas_right, 0, 2, 1, 2)
self.layout.addWidget(self.layout4_image_widget, 1, 0)
self.layout.addWidget(self.canvas_middle_top, 1, 1, 1, 2)
self.layout.addWidget(self.canvas_right_top, 1, 3)
# create a container widget and add it to the main layout
self.container = QWidget()
self.layout.addWidget(self.container, 2, 0)
containerLayout = QVBoxLayout(self.container)
# add the widgets to the container
containerLayout.addWidget(self.button_start)
containerLayout.addWidget(self.button_classification)
containerLayout.addWidget(self.LCD_Number)
# the remaining widgets on the third row
self.layout.addWidget(self.canvas_right_buttom, 2, 1, 1, 2)
self.layout.addWidget(self.canvas_middle_buttom, 2, 3)
self.layout.setColumnStretch(0, 3)
self.layout.setColumnStretch(1, 2)
self.layout.setColumnStretch(2, 2)
self.layout.setColumnStretch(3, 3)
# there are only 3 rows, the second and third have the same row span
self.layout.setRowStretch(0, 5)
self.layout.setRowStretch(1, 3)
self.layout.setRowStretch(2, 3)
In this case the space usage is more optimized, leaving more space to those widgets that need it (the LCD).
Upvotes: 2
Reputation: 144
maybe there is something to do with this function... as they say the stretch factor has something to do with the row's relative space occupation and its default value is 0. You could maybe try setting them at 1 for each row.
Upvotes: 0