PyQT5:如何在 QGridLayout 中自动对齐小部件?

时间:2021-05-28 12:31:18

标签: layout pyqt5

我在我的项目中使用 QGridLayout。我会在 QGridLayout 中自动添加一些小部件。因此,我实现了一个类 MultiWidgetLayout 来管理小部件。我的测试代码是:

import numpy as np
from PyQt5.QtWidgets import *
import sys
class MultiWidgetLayout(QGridLayout):

    def __init__(self):
        super().__init__()
        self.setSpacing(0)
        self.setContentsMargins(1,1,1,1)
        self.__widgets = []

    def getWidgetNum(self):
        return len(self.__widgets)

    def addWidget(self, widget):
        self.__widgets.append(widget)
        self.updateLayout()

    def setWidgets(self, widgets):
        self.__widgets = widgets
        self.updateLayout()

    def updateLayout(self):
        self.removeAllWidgets()
        n = len(self.__widgets)
        columns = int(np.ceil(np.sqrt(n)))
        rows = n//columns

        k = 0
        for r in range(rows):
            for c in range(columns):
                super().addWidget(self.__widgets[k], r, c)
                k += 1
        remain = n - columns*rows
        if remain > 0:
            for r in range(remain):
                super().addWidget(self.__widgets[k], rows, r)
                k += 1

        for widget in self.__widgets:
            widget.show()

    def removeAllWidgets(self):
        '''
        remove all the widgets
        '''
        N = self.count()
        for i in range(N-1,-1,-1):
            item = self.itemAt(i) # item is QHBoxLayout
            self.removeItem(item)
            # self.removeWidget(item)

        for widget in self.__widgets:
            widget.hide()

class Window(QWidget):

    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.setLayout(layout)
        self.multiWidgetLayout = MultiWidgetLayout()
        self.btn = QPushButton('add widget')
        self.btn.clicked.connect(self.addWidgetSlot)
        layout.addWidget(self.btn)
        layout.addLayout(self.multiWidgetLayout)

    def addWidgetSlot(self, check=False):
        num = self.multiWidgetLayout.getWidgetNum()
        label = QLabel(str(num))
        label.setStyleSheet('border: 2px solid red;')
        label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.multiWidgetLayout.addWidget(label)

if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    app.exec_()

这段代码基本上是我想要的,但是还有一个小问题。

当我添加三个小部件时,布局是:

enter image description here

但是,我希望 QLabel(2) 占据底行的整个空间。

5个小部件的布局是:

enter image description here

但是,我希望 QLable(3) 和 QLabel(4) 占据底行的整个空间。

感谢任何建议!

1 个答案:

答案 0 :(得分:1)

由于小部件将具有相似的大小、提示和策略,因此您可以将任何剩余的小部件添加到位于最后一行的水平布局中,跨越所有列。

考虑到没有必要删除小部件并再次添加它们,因为 addWidget() 会自动替换它们在布局中的位置并在需要时重新设置它们的父级,这也使得调用 { {1}}。
这很重要,原因有两个:

  1. show() 覆盖显式的 show()hide(),这不应该发生);
  2. 从布局中删除项目并不总是有效,因为项目的父级(小部件或布局)不会改变,并且可能导致意外行为;

另请注意,setVisible(False)sqrt 已由 ceil 模块提供,该模块是 Python 标准库的一部分。 Numpy 是一个相当大的模块,如果你不需要它用于其他任何东西,你将添加一个重要的要求,它会要求不必要的资源(不仅在内存中,还包括安装,如果不是实际的建设)。

在以下实现中,我使用了 math 来循环浏览所有小部件,因此不需要项目索引。

iter()