如何在Qt中用另一个小部件替换小部件?

14 投票
3 回答
25177 浏览
提问于 2025-04-16 09:34

我有一个 QHBoxLayout,左边是一个 QTreeWidget,中间是一个分隔符,右边是一个小部件。

当我点击 QTreeWidget 的时候,我想把右边的小部件换成一个可以修改 QTreeWidgetItem 的部件。

我试着用下面的代码来实现这个功能:

def new_rendez_vous(self):
    self.ui.horizontalLayout_4.removeWidget(self.ui.editionFormWidget)
    del self.ui.editionFormWidget
    self.ui.editionFormWidget = RendezVousManagerDialog(self.parent)
    self.ui.editionFormWidget.show()
    self.ui.horizontalLayout_4.addWidget(self.ui.editionFormWidget)
    self.connect(self.ui.editionFormWidget, QtCore.SIGNAL('saved'), self.scheduleTreeWidget.updateData)

def edit(self, category, rendez_vous):
    self.ui.horizontalLayout_4.removeWidget(self.ui.editionFormWidget)
    del self.ui.editionFormWidget
    self.ui.editionFormWidget = RendezVousManagerDialog(self.parent, category, rendez_vous)
    self.ui.editionFormWidget.show()
    self.ui.horizontalLayout_4.addWidget(self.ui.editionFormWidget)
    self.connect(self.ui.editionFormWidget, QtCore.SIGNAL('saved'), self.scheduleTreeWidget.updateData)

def edit_category(self, category):
    self.ui.horizontalLayout_4.removeWidget(self.ui.editionFormWidget)
    del self.ui.editionFormWidget
    self.ui.editionFormWidget = CategoryManagerDialog(self.parent, category)
    self.ui.editionFormWidget.show()
    self.ui.horizontalLayout_4.addWidget(self.ui.editionFormWidget)
    self.connect(self.ui.editionFormWidget, QtCore.SIGNAL('saved'), self.scheduleTreeWidget.updateData)

但是这样做不行,所有的小部件都堆叠在一起了:

这个bug的例子
(来源: free.fr)
.

你知道我该怎么去掉旧的小部件,然后显示新的那个吗?

3 个回答

18

其实,至少在Qt5中,有一种比B4adle7的解决方案更简洁的方法,那就是利用QLayout的replaceWidget功能。

containing_layout = placeholder.parent().layout()
containing_layout.replaceWidget(placeholder, new_widget)

额外提示:

如果你想在运行时放置一个自定义控件,并且你正在使用ui文件,那么不如直接使用自定义控件的推广功能!这里有一篇不错的帖子,里面有截图,讲解了如何在Qt设计器中配置自定义控件,适用于PyQt

PySide中,操作方式也类似。你不需要把自定义控件的源文件指定为头文件,而是要在加载ui文件的QUiLoader实例中,通过registerCustomWidget()方法来注册你的自定义控件类,使用Python代码来实现。

24

我和Natim有一样的问题。

QStackedWidget是一个用于预设布局的解决方案。它就像老式餐厅里的音乐盒翻页器(就像在点唱机里翻阅已安装的专辑)。

不过,这并没有解决我的问题。

比如说,我有一段代码在做原型设计,里面有一个用户界面布局,但我想把一些作为占位符的控件替换成在主脚本执行时编写的合适控件,或者是动态创建的控件。

我相信有一个简单的步骤或者注意事项可以正确地移除或替换一个控件。

我现在的代码里有一个基本的文本编辑控件在一个网格布局中。我想编写一个自定义版本的这个控件,用于拖放功能,然后把它替换掉默认的文本编辑控件。

就像Natim说的,代码看起来逻辑上是正确的,但控件在布局中像倾倒的手袋一样乱七八糟。

希望能找到解决这个问题的窍门,并重新分享这个注意事项。

解决方案:

太好了!!我找到了一个确实有效的方法。关闭你的控件。

#  Remove, Create, Replace
    self.ui.gridLayout.removeWidget(self.ui.dragDataEdit)
    self.ui.dragDataEdit.close()
    self.ui.dragDataEdit = myDumpBox(self.ui.centralwidget)
    self.ui.gridLayout.addWidget(self.ui.dragDataEdit, 0, 0, 1, 1)
    self.ui.gridLayout.update()

我从布局中移除了控件,然后关闭了这个控件。此时,我使用的变量可以用来创建我的自定义/修改过的控件,然后再把它插入到布局中。

是的,对于更复杂的布局,可能需要更优雅的处理,但要替换一个控件的基本需求就在于使用.close()方法。

干杯..希望这能帮到你。

23

最常见的解决办法是使用 QStackedWidget,把所有可能用到的控件放到这个堆栈里。当你选择一个项目时,只需要调用 setCurrentWidget 就可以显示你想要的那个控件。

撰写回答