如何以编程方式更改布局的父级

How do I programmatically change the parent of a layout

我希望能够根据用户输入将一个布局移动到另一个布局。我有以下代码似乎对我不起作用。如果我切换第 31 行和第 34 行,以便它们在小部件而不是布局上运行,那么我会得到预期的行为,但我希望通过移动布局来对布局内的所有小部件进行操作。

import sys

from PyQt5.QtWidgets import QPushButton, QWidget, QHBoxLayout, QLabel, QApplication, QVBoxLayout


class b(QWidget):
    def __init__(self, name):
        super(b, self).__init__()
        self.layout = QVBoxLayout(self)
        lbl_1 = QLabel(name)
        self.layout.addWidget(lbl_1)

class a(QWidget):
    def __init__(self):
        super(a, self).__init__()
        self.layout = QHBoxLayout(self)
        self.widget_1 = b('widget 1')
        self.widget_2 = b('widget 2')
        self.layout.addWidget(self.widget_1)
        self.layout.addWidget(self.widget_2)

        self.button_layout = QHBoxLayout()
        self.move_layout = QPushButton('Move to other layout')
        self.move_layout.clicked.connect(lambda: self.move_button())
        self.button_layout.addWidget(self.move_layout)
        self.widget = 'widget_2'
        self.widget_2.layout.addLayout(self.button_layout)

    def move_button(self):
        if self.widget == 'widget_2':
            self.widget_1.layout.addLayout(self.button_layout)
            self.widget = 'widget_1'
        else:
            self.widget_2.layout.addLayout(self.button_layout)
            self.widget = 'widget_2'
        print('moved widget to {}'.format(self.widget))

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

编辑:澄清一下,在上面的示例中,我要移动的布局 (self.button_layout) 是 self.widget_2.layout 的子布局。当我单击按钮时,我希望将 self.button_layout 设置为 self.widget_1.layout 的子布局。基本上它会做下面的代码所做的,但使用 addLayout 而不是 addWidget。

import sys

from PyQt5.QtWidgets import QPushButton, QWidget, QHBoxLayout, QLabel, QApplication, QVBoxLayout


class b(QWidget):
    def __init__(self, name):
        super(b, self).__init__()
        self.layout = QVBoxLayout(self)
        lbl_1 = QLabel(name)
        self.layout.addWidget(lbl_1)

class a(QWidget):
    def __init__(self):
        super(a, self).__init__()
        self.layout = QHBoxLayout(self)
        self.widget_1 = b('widget 1')
        self.widget_2 = b('widget 2')
        self.layout.addWidget(self.widget_1)
        self.layout.addWidget(self.widget_2)

        self.button_layout = QHBoxLayout()
        self.move_layout = QPushButton('Move to other layout')
        self.move_layout.clicked.connect(lambda: self.move_button())
        self.button_layout.addWidget(self.move_layout)
        self.widget = 'widget_2'
        self.widget_2.layout.addLayout(self.button_layout)

    def move_button(self):
        if self.widget == 'widget_2':
            self.widget_1.layout.addWidget(self.move_layout)
            self.widget = 'widget_1'
        else:
            self.widget_2.layout.addWidget(self.move_layout)
            self.widget = 'widget_2'
        print('moved widget to {}'.format(self.widget))

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

问题是,如果布局有父级,则无法更改,如错误消息所示:

QLayout::addChildLayout: layout "" already has a parent

一种可能的解决方案是删除父项:

def move_button(self):
    self.button_layout.setParent(None)
    if self.widget == "widget_2":
        self.widget_1.layout.addLayout(self.button_layout)
        self.widget = "widget_1"
    else:
        self.widget_2.layout.addLayout(self.button_layout)
        self.widget = "widget_2"
    print("moved widget to {}".format(self.widget))

另一种方法是将布局放置在作为容器的 QWidget 中,并将其放置在所需的布局中:

class a(QWidget):
    def __init__(self):
        super(a, self).__init__()
        layout = QHBoxLayout(self)
        self.widget_1 = b("widget 1")
        self.widget_2 = b("widget 2")
        layout.addWidget(self.widget_1)
        layout.addWidget(self.widget_2)

        self.container = QWidget()
        container_layout = QHBoxLayout(self.container)
        button = QPushButton("Move to other layout")
        button.clicked.connect(self.move_button)
        container_layout.addWidget(button)

        self.widget = "widget_1"
        self.move_button()

    def move_button(self):
        if self.widget == "widget_2":
            self.widget_1.layout.addWidget(self.container)
            self.widget = "widget_1"
        else:
            self.widget_2.layout.addWidget(self.container)
            self.widget = "widget_2"
        print("moved widget to {}".format(self.widget))