PyQt QGridLayout() 不当行为
PyQt QGridLayout() misbehaviour
我试图让 GUI 应用程序工作,但不幸的是,单个 canvas 对象的间距与预期不符。我想要以下布局:
对于网格布局,我使用以下代码:
# 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)
但不幸的是,我收到的结果是:
所以中间 5-7 行太宽了。
可能与此函数有关...因为他们说拉伸因子与行的相对 space 占用有关,其默认值为 0。您可以尝试设置它们每行 1 个。
对小部件使用列跨度和行跨度并不像您认为的那样有效。网格布局中的每个 "cell" 可能有不同的大小,这完全取决于 each 小部件 sizeHint 和 sizePolicy
.
所有小部件都有一个默认大小策略,这是一个 属性 小部件用来告诉其容器在调整大小时它的行为方式(如果它展开,有一个固定的 height/width,能不能缩水之类的)。
默认情况下,按钮和复选框具有 固定 垂直策略,这意味着它们永远不会增大或缩小。
每个布局都有一个可以为其每个 "slots" 分配的拉伸值。拉伸始终默认为 0,这让每个小部件都有可能增长或缩小以满足其需要,但是当设置该值时,可用的 spaces 由布局中每个拉伸的总和计算,然后平分。例如,如果您有一个包含 2 个小部件的简单布局,第一个小部件的 stretch=1,第二个小部件的 stretch=1,则可用的 space 将除以 3 (1 + 2),第一个占据第三个它和第二个三分之二。
对于网格布局,您可以使用 setRowStretch()
and setColumnStretch()
来实现您建议的效果,但这仅适用于具有兼容策略(首选或扩展)的小部件,并且由于在您的情况下这些按钮具有固定高度,因此不会够了。
有两种可能性,但在这两种情况下,我都会使用更简单的布局,因为由于上述原因和 setRowStretch
/[=17,不需要使用大量的行和列=] 可以改用。
布局仅使用 4 列:
+----+---+---+----+
| | |
+----+---+---+----+
| | | |
+----+---+---+----+
| | | |
+----+---+---+----+
第一行有两个 "cells",跨度为 2 列,接下来的行将 2 个中央槽合并为具有相似跨度的单个单元格。
1。手动设置这些小部件的政策
在这种情况下实际上有 5 行,第一行有 rowStretch=5,第二行有 3 行,其余 1 行。通过手动为小部件设置垂直大小策略,它们可以增长到所需的高度他们占据的行的范围。
# 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)
不幸的是,这并不完美:如您所见,按钮可能会变得太大,并且复选框有很多不必要的边距,LCD 小部件可能会使用这些边距。
2。使用容器小部件
在这种情况下只有 3 行,并且一个额外的 QWidget 用作左下角小部件的容器。
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)
在这种情况下,space 的使用更加优化,将更多 space 留给需要它的小部件(LCD)。
我试图让 GUI 应用程序工作,但不幸的是,单个 canvas 对象的间距与预期不符。我想要以下布局:
对于网格布局,我使用以下代码:
# 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)
但不幸的是,我收到的结果是:
所以中间 5-7 行太宽了。
可能与此函数有关...因为他们说拉伸因子与行的相对 space 占用有关,其默认值为 0。您可以尝试设置它们每行 1 个。
对小部件使用列跨度和行跨度并不像您认为的那样有效。网格布局中的每个 "cell" 可能有不同的大小,这完全取决于 each 小部件 sizeHint 和 sizePolicy
.
所有小部件都有一个默认大小策略,这是一个 属性 小部件用来告诉其容器在调整大小时它的行为方式(如果它展开,有一个固定的 height/width,能不能缩水之类的)。
默认情况下,按钮和复选框具有 固定 垂直策略,这意味着它们永远不会增大或缩小。
每个布局都有一个可以为其每个 "slots" 分配的拉伸值。拉伸始终默认为 0,这让每个小部件都有可能增长或缩小以满足其需要,但是当设置该值时,可用的 spaces 由布局中每个拉伸的总和计算,然后平分。例如,如果您有一个包含 2 个小部件的简单布局,第一个小部件的 stretch=1,第二个小部件的 stretch=1,则可用的 space 将除以 3 (1 + 2),第一个占据第三个它和第二个三分之二。
对于网格布局,您可以使用 setRowStretch()
and setColumnStretch()
来实现您建议的效果,但这仅适用于具有兼容策略(首选或扩展)的小部件,并且由于在您的情况下这些按钮具有固定高度,因此不会够了。
有两种可能性,但在这两种情况下,我都会使用更简单的布局,因为由于上述原因和 setRowStretch
/[=17,不需要使用大量的行和列=] 可以改用。
布局仅使用 4 列:
+----+---+---+----+
| | |
+----+---+---+----+
| | | |
+----+---+---+----+
| | | |
+----+---+---+----+
第一行有两个 "cells",跨度为 2 列,接下来的行将 2 个中央槽合并为具有相似跨度的单个单元格。
1。手动设置这些小部件的政策
在这种情况下实际上有 5 行,第一行有 rowStretch=5,第二行有 3 行,其余 1 行。通过手动为小部件设置垂直大小策略,它们可以增长到所需的高度他们占据的行的范围。
# 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)
不幸的是,这并不完美:如您所见,按钮可能会变得太大,并且复选框有很多不必要的边距,LCD 小部件可能会使用这些边距。
2。使用容器小部件
在这种情况下只有 3 行,并且一个额外的 QWidget 用作左下角小部件的容器。
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)
在这种情况下,space 的使用更加优化,将更多 space 留给需要它的小部件(LCD)。