Qt删除布局内的控件

基于某些原因,我们可能希望往一个布局内动态删除和添加新的元素,添加我们都能很清楚得看到addWidget这个接口.删除的话官方也有示例:


    QLayoutItem *child;
    while(child=this->ui->centralWidget->layout()->takeAt(0)) {
        delete child;
    }


不知道是我个人理解的角度有问题还是怎么,我感觉就很奇怪,我添加一个widget的时候,是传入widget的指针,删除的时候是删除一个QLayoutItem的指针,读了半天的源代码才明白,在addWidget的时候,做了这样一些操作

void QLayout::addWidget(QWidget *w)
{
    addChildWidget(w);
    addItem(QLayoutPrivate::createWidgetItem(this, w));
}

先将传入的widget指针交给layout的所属widget,这样就实现了传入的widget成为了另一个widget的子widget,接着在删除父widget时会清理(析构)这个子widget.

void QLayout::addChildWidget(QWidget *w)
{
    QWidget *mw = parentWidget();
    QWidget *pw = w->parentWidget();
 
    //Qt::WA_LaidOut is never reset. It only means that the widget at some point has
    //been in a layout.
    if (pw && w->testAttribute(Qt::WA_LaidOut)) {
        QLayout *l = pw->layout();
        if (l && removeWidgetRecursively(l, w)) {
#ifdef QT_DEBUG
            if (layoutDebug())
                qWarning("QLayout::addChildWidget: %s \"%s\" is already in a layout; moved to new layout",
                         w->metaObject()->className(), w->objectName().toLocal8Bit().data());
#endif
        }
    }
    if (pw && mw && pw != mw) {
#ifdef QT_DEBUG
            if (layoutDebug())
                qWarning("QLayout::addChildWidget: %s \"%s\" in wrong parent; moved to correct parent",
                         w->metaObject()->className(), w->objectName().toLocal8Bit().data());
#endif
        pw = 0;
    }
    bool needShow = mw && mw->isVisible() && !(w->isHidden() && w->testAttribute(Qt::WA_WState_ExplicitShowHide));
    if (!pw && mw)
        w->setParent(mw);
    w->setAttribute(Qt::WA_LaidOut);
    if (needShow)
        QMetaObject::invokeMethod(w, "_q_showIfNotHidden", Qt::QueuedConnection); //show later
}
 
然后addItem是一个纯虚接口,createWidgetItem是一个工厂接口
QLayoutPrivate::QWidgetItemFactoryMethod QLayoutPrivate::widgetItemFactoryMethod = 0;
QLayoutPrivate::QSpacerItemFactoryMethod QLayoutPrivate::spacerItemFactoryMethod = 0;
QWidgetItem *QLayoutPrivate::createWidgetItem(const QLayout *layout, QWidget *widget)
{
    if (widgetItemFactoryMethod)
        if (QWidgetItem *wi = (*widgetItemFactoryMethod)(layout, widget))
            return wi;
    return new QWidgetItemV2(widget);
}
应该是依据相应的widget,生成相应的widgetItem(派生自QLayoutItem)
后面的就没继续读了
大意就是根据widget生成一个item加入到layout的item链表中.
 
接着删除的代码就能了解了,就是对这个item的链表进行清理,可以看到这个过程中没有涉及到widget的析构,所以layout清理完item之后,被加入到layout的widget没有析构掉,但这个时候原先加入进的子widget,这个时候其父widget并没有被恢复到之前的父widget.
import sys from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout class MainWindow(QWidget): def init(self, data): super().init() # 创建界面元素 self.label1 = QLabel("坐标") self.label4 = QLabel("类别") self.button1 = QPushButton("1 ") self.button2 = QPushButton("2 ") self.button3 = QPushButton("3 ") self.button4 = QPushButton("4 ") self.button = QPushButton("确定") self.exit_button = QPushButton("退出") # 创建布局管理器 layout = QVBoxLayout() layout.addWidget(self.label1) layout.addWidget(self.label4) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) layout.addWidget(self.button4) layout.addWidget(self.button) layout.addWidget(self.exit_button) # 退出 # 设置界面布局 self.setLayout(layout) # 为按钮添加点击事件 self.button1.clicked.connect(lambda: self.show_info(data[0])) self.button2.clicked.connect(lambda: self.show_info(data[1])) self.button3.clicked.connect(lambda: self.show_info(data[2])) self.button4.clicked.connect(lambda: self.show_info(data[3])) self.button.clicked.connect(lambda: self.show_upper_info())#确定 self.exit_button.clicked.connect(lambda: self.close()) # 为退出按钮添加点击事件 self.setFixedSize(500, 300) def show_info(self, info): # 显示信息 self.label1.setText("坐标:" + str(info[0])+","+str(info[1])+","+str(info[2])+","+str(info[3])) self.label4.setText("类别:" + str(info[4])) def show_upper_info(self): # 获取当前显示的信息 upper_info = self.label1.text() + "\n" + self.label4.text() # 在控制台输出上位机信息 print("\n" + upper_info) if name == 'main': # 假设这是程序输出的信息 data = [ [123, 456,"宽","高", "类别"], [234, 567,"宽", "高", "类别"], [345, 678, "宽", "高", "类别"], [456, 789, "宽", "高", "类别"], ] # 创建应用程序和窗口 app = QApplication(sys.argv) window = MainWindow(data) window.show() # 运行应用程序 sys.exit(app.exec_())将这个程序data的输入改为另一个程序的print输出
05-10
如果你想将这个程序的data输入改为另一个程序的print输出,你可以使用Python的subprocess模块来实现。具体来说,你可以使用subprocess.Popen()函数来运行第二个程序,并通过管道来获取它的输出。然后,你可以将这个输出解析为一个数据列表,并将其传递给MainWindow类的构造函数。下面是一个示例代码: ``` import sys import subprocess from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout class MainWindow(QWidget): def __init__(self, data): super().__init__() # 创建界面元素 self.label1 = QLabel("坐标") self.label4 = QLabel("类别") self.button1 = QPushButton("1 ") self.button2 = QPushButton("2 ") self.button3 = QPushButton("3 ") self.button4 = QPushButton("4 ") self.button = QPushButton("确定") self.exit_button = QPushButton("退出") # 创建布局管理器 layout = QVBoxLayout() layout.addWidget(self.label1) layout.addWidget(self.label4) layout.addWidget(self.button1) layout.addWidget(self.button2) layout.addWidget(self.button3) layout.addWidget(self.button4) layout.addWidget(self.button) layout.addWidget(self.exit_button) # 退出 # 设置界面布局 self.setLayout(layout) # 为按钮添加点击事件 self.button1.clicked.connect(lambda: self.show_info(data[0])) self.button2.clicked.connect(lambda: self.show_info(data[1])) self.button3.clicked.connect(lambda: self.show_info(data[2])) self.button4.clicked.connect(lambda: self.show_info(data[3])) self.button.clicked.connect(lambda: self.show_upper_info())#确定 self.exit_button.clicked.connect(lambda: self.close()) # 为退出按钮添加点击事件 self.setFixedSize(500, 300) def show_info(self, info): # 显示信息 self.label1.setText("坐标:" + str(info[0])+","+str(info[1])+","+str(info[2])+","+str(info[3])) self.label4.setText("类别:" + str(info[4])) def show_upper_info(self): # 获取当前显示的信息 upper_info = self.label1.text() + "\n" + self.label4.text() # 在控制台输出上位机信息 print("\n" + upper_info) if __name__ == '__main__': # 假设这是第二个程序的输出 output = "123,456,宽,高,类别\n234,567,宽,高,类别\n345,678,宽,高,类别\n456,789,宽,高,类别\n" # 运行第二个程序并获取输出 proc = subprocess.Popen(["python", "second_program.py"], stdout=subprocess.PIPE) output, error = proc.communicate() # 将输出解析为数据列表 data = [line.strip().split(",") for line in output.decode().split("\n") if line.strip()] # 创建应用程序和窗口 app = QApplication(sys.argv) window = MainWindow(data) window.show() # 运行应用程序 sys.exit(app.exec_()) ``` 在这个示例代码,我们假设第二个程序的输出是一个逗号分隔的文本字符串,每一行表示一个数据项。我们使用subprocess.Popen()函数来运行第二个程序,并将其输出通过管道传递给我们的程序。然后,我们使用output.decode()将输出的字节字符串解码为一个普通字符串,并将其按行分隔。我们使用strip()方法来删除每行开头和结尾的空格和换行符,并使用split(",")方法将每行分隔为一个数据列表。最后,我们将这些数据列表组成的列表传递给MainWindow类的构造函数。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值