删除小部件后布局不正确

The layout is incorrect after remove widget

我正在使用 pyqt5 实现我的项目。目前,我有一个 window 包括许多小部件。现在,我想删除一些小部件。 window 看起来像:

现在,我想删除 'name1' 小部件,包括 QLabel 和 QPushButton。

但是,在移除所有'name1' widgets后,包括QLabel和QPushButton在内的'name2' widgets无法与window自适应,如:

我所有的代码是:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Window(QDialog):

    def __init__(self):
        super().__init__()
        self.initGUI()
        self.show()

    def initGUI(self):
        layout = QVBoxLayout()
        self.setLayout(layout)

        removeLayout = QHBoxLayout()
        self.__removeText = QLineEdit()

        self.__removeBtn = QPushButton('Remove')
        self.__removeBtn.clicked.connect(self.remove)
        removeLayout.addWidget(self.__removeText)
        removeLayout.addWidget(self.__removeBtn)

        ROIsLayout = QVBoxLayout()
        for name in ['name1', 'name2']:
            subLayout = QHBoxLayout()
            subText = QLabel(name)
            subText.setObjectName(name)
            subBtn = QPushButton(name)
            subBtn.setObjectName(name)

            subLayout.addWidget(subText)
            subLayout.addWidget(subBtn)
            ROIsLayout.addLayout(subLayout)

        layout.addLayout(removeLayout)
        layout.addLayout(ROIsLayout)
        self.__ROIsLayout = ROIsLayout


    def remove(self, checked=False):
        name = self.__removeText.text()
        while True:
            child = self.__ROIsLayout.takeAt(0)
            if child == None:
                break
            while True:
                subChild = child.takeAt(0)
                if subChild == None:
                    break
                obName = subChild.widget().objectName()
                if name == obName:
                    widget = subChild.widget()
                    widget.setParent(None)
                    child.removeWidget(widget)
                    self.__ROIsLayout.removeWidget(widget)
                    del widget

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

更新:

实际上,问题可能出在 takeAt。以下代码是可行的:

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import sys

class Window(QDialog):

    def __init__(self):
        super().__init__()
        self.initGUI()
        self.show()

    def initGUI(self):
        layout = QVBoxLayout()
        self.setLayout(layout)

        removeLayout = QHBoxLayout()
        self.__removeText = QLineEdit()

        self.__removeBtn = QPushButton('Remove')
        self.__removeBtn.clicked.connect(self.remove)
        removeLayout.addWidget(self.__removeText)
        removeLayout.addWidget(self.__removeBtn)

        ROIsLayout = QVBoxLayout()
        for name in ['name1', 'name2']:
            subLayout = QHBoxLayout()
            subLayout.setObjectName(name)
            subText = QLabel(name, parent=self)
            subText.setObjectName(name)
            subBtn = QPushButton(name, parent=self)
            subBtn.setObjectName(name)

            subLayout.addWidget(subText)
            subLayout.addWidget(subBtn)
            ROIsLayout.addLayout(subLayout)
            print(name, subLayout, subText, subBtn)

        layout.addLayout(removeLayout)
        layout.addLayout(ROIsLayout)
        self.__ROIsLayout = ROIsLayout

        self.record = [subLayout, subText, subBtn]


    def remove(self, checked=False):

        
        layout = self.record[0]
        txt = self.record[1]
        btn = self.record[2]

        layout.removeWidget(txt)
        txt.setParent(None)
        txt.deleteLater()

        layout.removeWidget(btn)
        btn.setParent(None)
        btn.deleteLater()

if __name__ == '__main__':

    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

但是,我在 self.record 中打印了 QLabel/QPushButton,我发现它与 child.takeAt(0).widget().[=15 中的相同=]

您代码中的主要问题是您一直在使用 takeAt()。结果是 __ROIsLayout 布局中的所有项目都将从中删除(但不会删除),在您的情况下,它们是子布局。这显然不是一个好方法:只有具有相应对象名称的小部件才会被实际删除,而其他小部件仍将由其先前的父级“拥有”,仍将在其先前的位置可见,并且它们的几何图形不会被删除已更新,因为它们不再由布局管理。

您的问题有多种解决方案,具体取决于您的需要。

如果您需要从布局中删除 ,我会考虑改为在布局上设置对象名称,并使用 self.findChild() 查找它。

另请考虑,虽然 Qt 允许为多个对象设置相同的对象名称,但不建议这样做。

最后,虽然通常使用 del 就足够了,但通常最好为所有 Qt 对象调用 deleteLater(),这样可以确保 Qt 正确删除所有对象(以及相关的 parentship/connections) .

对于这种特定情况,另一种可能性是使用 QFormLayout