Qt主窗口动态切换中央部件报错:wrapped c/c++ object已删除
解决QMainWindow切换中央部件时控件被销毁的问题
嘿,我完全懂你遇到的困扰——前几次点击按钮还正常,之后就弹出控件已被删除的报错,这其实是Qt的对象父子销毁机制在起作用,咱们一步步拆解问题和解决方案:
问题根源
当你调用self.setCentralWidget(wid)时,Qt会自动销毁上一次设置的中央部件(也就是之前创建的那个wid对象)。而你把self.lineedit、self.checkbox这些控件添加到了wid的布局里后,这些控件会自动成为wid的子对象。根据Qt的规则:父对象被销毁时,所有子对象会被一并销毁。
所以第一次切换后,旧的wid被删除,里面的那个随机选中的控件也跟着没了。之后再尝试把这个已经被销毁的控件加到新布局里,自然就会触发“wrapped c/c++ object has been deleted”的报错。
两种解决方案
方案1:每次创建新的控件实例(简单直接)
如果不需要保留控件的状态(比如输入的文本、勾选状态),可以每次随机生成新的控件对象,这样就不会遇到旧对象被销毁的问题:
import sys import random from PyQt5 import QtWidgets class window25(QtWidgets.QMainWindow): def __init__(self): try: super(window25,self).__init__() self.btn=QtWidgets.QPushButton("press me") self.guichange() self.btn.clicked.connect(self.guichange) self.show() except Exception as E: print(E) def guichange(self): try: wid=QtWidgets.QWidget() myLayout=QtWidgets.QVBoxLayout() myLayout.addWidget(self.btn) # 每次随机创建新的控件实例 chosen_widget = random.choice([ QtWidgets.QLineEdit(), QtWidgets.QCheckBox(), QtWidgets.QRadioButton() ]) myLayout.addWidget(chosen_widget) wid.setLayout(myLayout) self.setCentralWidget(wid) except Exception as E: print(E) app=QtWidgets.QApplication([]) ex=window25() sys.exit(app.exec_())
方案2:复用原有控件并避免被销毁(保留状态)
如果需要保留控件的状态(比如输入的文本、勾选状态),可以在每次切换前把控件从旧布局中移除,并解除它们和旧父对象的关联:
import sys import random from PyQt5 import QtWidgets class window25(QtWidgets.QMainWindow): def __init__(self): try: super(window25,self).__init__() # 保存所有需要复用的控件到列表 self.reusable_widgets = [ QtWidgets.QLineEdit(), QtWidgets.QCheckBox(), QtWidgets.QRadioButton() ] self.btn=QtWidgets.QPushButton("press me") self.guichange() self.btn.clicked.connect(self.guichange) self.show() except Exception as E: print(E) def guichange(self): try: wid=QtWidgets.QWidget() myLayout=QtWidgets.QVBoxLayout() myLayout.addWidget(self.btn) # 先解除所有复用控件和旧父对象的关联 for widget in self.reusable_widgets: if widget.parent() is not None: widget.setParent(None) # 随机选择一个控件添加到新布局 chosen_widget = random.choice(self.reusable_widgets) myLayout.addWidget(chosen_widget) wid.setLayout(myLayout) self.setCentralWidget(wid) except Exception as E: print(E) app=QtWidgets.QApplication([]) ex=window25() sys.exit(app.exec_())
改动说明
- 方案1去掉了初始化时创建的控件实例,每次切换都生成新对象,彻底避免了旧对象被销毁的问题。
- 方案2通过
widget.setParent(None)解除控件和旧父对象的绑定,这样旧的中央部件被销毁时,这些控件不会被连带删除,就能安全复用了。
内容的提问来源于stack exchange,提问作者Nimish Bansal
相关产品推荐
相关产品推荐

