PyQt5 QGridLayout 大小不正确

Posted

技术标签:

【中文标题】PyQt5 QGridLayout 大小不正确【英文标题】:PyQt5 QGridLayout sizing incorrect 【发布时间】:2020-01-03 01:53:46 【问题描述】:

我在 pyqt5 中遇到了 QGridLayout 的一些问题。我正在尝试制作一个 GUI,它的一侧有一堆按钮,另一侧有一个表格,还有一个占据整个窗口底部的绘图。这是我制作的第一个程序,所以我可能遇到的问题比我知道的要多。

我在 QTableWidget 中安排了按钮,主 QTableWidget 包含几个用户可以输入数据的字段。我希望数据输入表的大小比按钮表大,但是像this 答案中那样调整它的大小似乎没有任何作用。无论我输入的 columnSpan 条目如何,按钮表都更大。我做错了什么?

以下是相关的代码:

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setGeometry(50, 50, 700, 1000)
        self.home()

    def home(self):
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.button_table = QTableWidget(self)  
        self.layer_add = QPushButton("Add layer", self)       
        self.plotter = QPushButton("plot transmission", self)

        self.layer_table = QTableWidget(self)

        self.graphWidget = pg.PlotWidget(self)

        self.grid = QGridLayout()
        self.grid.setSpacing(10)
        self.grid.addWidget(self.button_table, 0, 0, 1, 1)
        self.grid.addWidget(self.layer_table, 0, 1, 1, 3)
        self.grid.addWidget(self.graphWidget, 1, 0, 1, 4)      
        self.centralWidget().setLayout(self.grid)
        self.show()

我涂鸦了我最希望发生的事情......这是上面代码的样子

我希望发生的事情是红色的。

编辑:我不明白为什么,如果我将左侧表格的 QGridLayout columnSpan 设置为 1,右侧表格设置为 3,左侧表格仍然明显更宽。我愿意学习如何解决这个问题,了解如何使左侧表格自动缩小到其中按钮的大小,或者提供替代布局建议。感谢您的帮助!

【问题讨论】:

您好,欢迎来到 ***!为了将来参考,请确保您提供minimal, reproducible example;幸运的是,您的代码只需要很少的调整,但即使对于愿意提供帮助的人来说,如果他们意识到他们需要调整您的代码以使其正常工作,这仍然会很烦人:我只花了一分钟,但你不能指望每个人都愿意这样做。就是说,让我明白:您是否希望左上角的表格自动调整其内容的大小,以便右上角的表格尽可能多地使用空间? 嗨@musicamante。我已经编辑了代码以使其更具可读性。我想:要么让左上角的表格调整自己的大小以适应内容,以便为右上角的表格提供更多空间,要么解释我如何错误地设置 QGridLayout,或者寻求另一种布局解决方案(网格在网格?网​​格中的垂直布局?可以这样做吗?)。我不认为我有能力在 QTDesigner 中进行布局,并且无论如何学习如何做都超出了本练习的范围。任何帮助表示赞赏!谢谢! 【参考方案1】:

虽然您回答了自己的问题,但您似乎通过删除第一个表来改变行为(此外,更改第一列拉伸的调整大小模式与您的问题没有太大关系)。因此,我正在回答您的 [已编辑] 问题,即使它缺少您将按钮添加到第一个表格的部分。

主要问题是您为第二个表设置了太大的列跨度:

    self.grid.addWidget(self.button_table, 0, 0, 1, 1)
    self.grid.addWidget(self.layer_table, 0, 1, 1, 3) # <- 3 columns!
    self.grid.addWidget(self.graphWidget, 1, 0, 1, 4)      

在上面的代码中,您告诉布局layer_table 将有一个列跨度 3 列。即使您实际上并未使用三列,通过这样做,布局认为第二个表格将(可能)比第一个表格占据更多空间。 通常,QGridLayout 将为此使用 columnStretch 属性,但由于默认情况下所有列和行的拉伸为 0,因此它将使用跨度作为参考。

其实使用如下:

    self.grid.addWidget(self.button_table, 0, 0, 1, 1)
    self.grid.addWidget(self.layer_table, 0, 1, 1, 1) # <- 1 column!
    self.grid.addWidget(self.graphWidget, 1, 0, 1, 2)      

和这个是一样的:

    self.grid.addWidget(self.button_table, 0, 0, 1, 1)
    self.grid.addWidget(self.layer_table, 0, 1, 1, 3) # <- 3 columns!
    self.grid.addWidget(self.graphWidget, 1, 0, 1, 4)      
    self.grid.setColumnStretch(0, 1)
    self.grid.setColumnStretch(1, 1)

在第一种情况下,列跨度为 1(一个小部件,一列),并且由于两个小部件属于同一类型,因此它们将使用可用水平空间的一半。在第二个中,右表的列跨度为 3(如您的代码中所示),第一列和第二列的拉伸为 1,而第二列的拉伸为 0第三和第四,这意味着占据第二、第三和第四列的小部件将具有与占据第一列的小部件相同的可用空间,从而获得在这两个小部件之间平均分配的水平空间。

col1 | col2 | col3 | col4
  1  |   1  |   0  |  0

由于第二个表占据了第 2 到第 4 列,它的长度为 1 (1 + 0 + 0)。布局使用拉伸来平均划分小部件之间的空间(考虑它们的尺寸提示、最小尺寸提示或设置时的最小/最大尺寸):拉伸是整数值的总和,然后布局使用比例在总和和这些值之间调整小部件的大小。

为确保第一个表仅使用显示其内容所需的最小空间,您需要执行以下操作:

    sizeAdjustPolicy(每个QAbstractScrollArea 后代的属性,包括每个项目视图)设置为AdjustToContents;这将使表格“告诉”布局其大小提示基于其最小内容; 设置horizontal header 的resize mode 以将其所有部分(如)调整为其内容; 设置表格的横向大小策略为Maximum;术语“最大”可能违反直觉,但这意味着小部件的尺寸不能大于其尺寸提示;尽管如此,如果任何其他小部件需要空间(但不小于minimumSizeHint),它可以缩小,因此,或者,您可以使用Fixed(意味着它甚至不能缩小),但它是如果布局太拥挤并且用户需要使窗口小于实际值,通常最好允许小部件缩小;
class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setGeometry(50, 50, 700, 1000)
        self.home()

    def home(self):
        self.central_widget = QWidget()
        self.setCentralWidget(self.central_widget)

        self.button_table = QTableWidget(self)
        self.button_table.setRowCount(3)
        self.button_table.setColumnCount(1)

        # set the sizeHint of the table view (actually, its ancestor class,
        # QAbstractScrollArea) to the minimum size required to show its contents
        self.button_table.setSizeAdjustPolicy(self.button_table.AdjustToContents)

        # set all sections of the horizontal headers to adjust themselves to
        # their contents
        self.button_table.horizontalHeader().setSectionResizeMode(
            QHeaderView.ResizeToContents)

        # get the current sizePolicy and set it to Maximum, meaning that it will
        # use its sizeHint as "maximum": it can expand, but there's no need for
        # that, so if any other sibling widget requires more space, it can use it
        policy = self.button_table.sizePolicy()
        policy.setHorizontalPolicy(policy.Maximum)
        # apply the changed policy
        self.button_table.setSizePolicy(policy)

        self.layer_add = QPushButton("Add layer", self)       
        self.plotter = QPushButton("plot transmission", self)
        # I restored the following lines, which were missing in your edit
        self.button_table.setCellWidget(0, 0, self.layer_add)
        self.button_table.setCellWidget(1, 0, self.plotter)

        self.layer_table = QTableWidget(self)

        self.graphWidget = pg.PlotWidget(self)

        self.grid = QGridLayout()
        self.grid.setSpacing(10)
        self.grid.addWidget(self.button_table, 0, 0, 1, 1)
        self.grid.addWidget(self.layer_table, 0, 1, 1, 1)
        self.grid.addWidget(self.graphWidget, 1, 0, 1, 2)
        self.centralWidget().setLayout(self.grid)

如您所见,现在左表仅使用最小所需宽度,基于水平标题宽度(加上垂直标题宽度),而垂直标题宽度又基于每列最大宽度的总和。

【讨论】:

【参考方案2】:

事实证明,在第 1 列上使用 setColumnStretch 解决了这个问题。我还将左表更改为 QVBoxLayout 并使用 QGridLayout.addLayout 将其放入,所以现在一切看起来都更好了

我仍然不太明白为什么这两个表格在 QGridLayout 上的宽度不相等,不管选择的列数是多少。

【讨论】:

以上是关于PyQt5 QGridLayout 大小不正确的主要内容,如果未能解决你的问题,请参考以下文章

PyQT 按钮在 QGridLayout 中的大小不正确

PyQT5 正确的布局对齐

PyQt5-网格布局(QGridLayout)-11

PyQt5-网格布局(QGridLayout)-10

将图像插入 QGridLayout 并在 PyQt5 中的图像顶部绘制

如何在 PyQt5 中为 QGridLayout 添加拉伸?