【问题标题】:How to insert QWidgets in the middle of a Layout?如何在布局中间插入 QWidgets?
【发布时间】:2017-06-24 09:41:31
【问题描述】:

我正在使用 Qt 框架来构建我的图形用户界面。我使用 QGridLayout 来整齐地放置我的 QWidget。
GUI 如下所示:

我的应用程序会在运行时定期向 GUI 添加新的小部件。这些新的小部件通常不会添加到 QLayout 的末尾,而是添加到中间的某个位置。

执行此操作的过程有点麻烦。应用于上图,我需要从 QGridLayout 中取出 widg_C, widg_D, ...。接下来,我添加widg_xwidg_y,最后我将其他小部件重新放回原处。
这就是我从 QGridLayout 中删除小部件的方式:

for i in reversed(range(myGridLayout.count())):
    self.itemAt(i).widget().setParent(None)
###

只要您处理少量的小部件,这个过程就不是灾难。但是在我的应用程序中,我显示了很多小部件——可能有 50 个或更多!执行此过程时,应用程序会冻结一秒钟,这对用户来说非常烦人。
有没有办法在 QLayout 的某处插入小部件,而不需要取出其他小部件?


编辑: 显然 QVBoxLayout 的解决方案非常简单。只需使用函数insertWidget(..) 而不是addWidget(..)。可以在此链接中找到文档:http://doc.qt.io/qt-5/qboxlayout.html#insertWidget
不幸的是,我找不到 QGridLayout 的类似功能。


编辑: 许多人正确地提到,放回很多小部件不会导致性能问题 - 它确实非常快(感谢@ekhumoro 指出这一点)。显然,我面临的性能问题与放回小部件的算法有关。这是一个相当复杂的递归算法,它将每个小部件放在 QGridLayout 中的正确坐标上。这导致我的显示器出现“闪烁”。小部件被取出,并延迟放回内部(由于算法) - 导致闪烁。


编辑: 我找到了一个解决方案,可以轻松地将新行插入 QGridLayout。插入新行意味着我不需要从头开始取出并替换所有小部件 - 因此我避免了运行昂贵的递归算法。
可以在下面我的回答中找到解决方案。

【问题讨论】:

  • 关于QVBoxLayout,有insertWidget方法,还有一些类似的问题。
  • 我认为您为您的 GUI 选择了错误的模型。例如,对于此类动态内容,您可以使用QTableWidget。它将处理所有项目的插入/删除等。
  • 你的插入小部件的代码肯定有问题,因为50个小部件是一个微不足道的数字。我做了一些测试,在包含 2000 个小部件的布局顶部插入一个小部件并将所有其他小部件向下移动只需不到半秒的时间。
  • @ekhumoro 我认为这取决于小部件的 resizeEvent() 完成了多少工作。从记忆中,我似乎记得每当您更改任何内容时,Qt 都会生成内部“布局更改”事件。这些最终作为对小部件上的 resizeEvent() 的调用(或者可能只是对 moveEvent() 的调用)。无论如何,如果您在其中有重要的代码,就会导致性能问题。
  • @StuartFisher。这一切都属于我的意思:“你的代码有问题”。 OP 需要提供一个 minimal reproducible example 来演示该行为,否则问题没有实际意义。

标签: python qt python-3.x pyqt pyqt5


【解决方案1】:

感谢 @ekhumoro、@Stuart Fisher、@vahancho 和 @mbjoe 的帮助。我最终找到了解决问题的方法。我不再使用QGridLayout()。相反,我围绕 QVBoxLayout 构建了一个包装器,使其表现得好像它是一个 GridLayout,并具有插入新行的额外功能:

class CustomGridLayout(QVBoxLayout):
    def __init__(self):
        super(CustomGridLayout, self).__init__()
        self.setAlignment(Qt.AlignTop)  # !!!
        self.setSpacing(20)


    def addWidget(self, widget, row, col):
        # 1. How many horizontal layouts (rows) are present?
        horLaysNr = self.count()

        # 2. Add rows if necessary
        if row < horLaysNr:
            pass
        else:
            while row >= horLaysNr:
                lyt = QHBoxLayout()
                lyt.setAlignment(Qt.AlignLeft)
                self.addLayout(lyt)
                horLaysNr = self.count()
            ###
        ###

        # 3. Insert the widget at specified column
        self.itemAt(row).insertWidget(col, widget)

    ''''''

    def insertRow(self, row):
        lyt = QHBoxLayout()
        lyt.setAlignment(Qt.AlignLeft)
        self.insertLayout(row, lyt)

    ''''''

    def deleteRow(self, row):
        for j in reversed(range(self.itemAt(row).count())):
            self.itemAt(row).itemAt(j).widget().setParent(None)
        ###
        self.itemAt(row).setParent(None)

    def clear(self):
        for i in reversed(range(self.count())):
            for j in reversed(range(self.itemAt(i).count())):
                self.itemAt(i).itemAt(j).widget().setParent(None)
            ###
        ###
        for i in reversed(range(self.count())):
            self.itemAt(i).setParent(None)
        ###

    ''''''

【讨论】:

    猜你喜欢
    • 2012-08-17
    • 2021-11-23
    • 1970-01-01
    • 2021-08-10
    • 1970-01-01
    • 1970-01-01
    • 2015-03-21
    • 2021-11-11
    • 2015-01-05
    相关资源
    最近更新 更多