class window25(QtWidgets.QMainWindow):
def __init__(self):
try:
super(window25,self).__init__()
self.lineedit=QtWidgets.QLineEdit()
self.checkbox=QtWidgets.QCheckBox()
self.optBox=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()
# self.setCentralWidget()
myLayout=QtWidgets.QVBoxLayout()
myLayout.addWidget(self.btn)
myLayout.addWidget(random.choice([self.lineedit,self.checkbox,self.optBox]))
wid.setLayout(myLayout)
self.setCentralWidget(wid)
except Exception as E:
print(E)
app=QtWidgets.QApplication([])
ex=window25()
sys.exit(app.exec_())
我正在尝试进行实验。虽然我知道 QStackedWidget 可以更改窗口,但我尝试了其他方法,即按下按钮随机更改 mainWindow Central 小部件。几次成功后(即按下按钮 3,4 次工作正确”)但在那之后我得到了一个错误
wrapped c/c++ object of type QCheckBox has been deleted
wrapped c/c++ object of type QLineEdit has been deleted
我无法理解是哪条语句导致了这个错误,以及为什么或哪里错了
最佳答案
这是由 Qt 的实现和理念引起的,回顾 documentation观察到:
[...]
QObjects organize themselves in object trees. When you create a QObject with another object as parent, the object will automatically add itself to the parent's children() list. The parent takes ownership of the object; i.e., it will automatically delete its children in its destructor. You can look for an object by name and optionally type using findChild() or findChildren().
[...]
正如他所说,如果父级也破坏了子级,并且由于所有小部件都以 QObject
作为它们的前身,它们也遵守这些规则。
但为什么有些小部件被销毁了?
每次您使用 setCentralWidget()
时,之前作为中央小部件的对象都会被删除。
CentralWidget() 的子项是什么?
当小部件附加到布局时,这些小部件将设置为使用该布局的小部件的父级。
wid = QtWidgets.QWidget()
myLayout.addWidget(tmp)
wid.setLayout(myLayout)
self.setCentralWidget(wid)
为什么QPushButton没有被淘汰?
QPushButton
以及有时其他小部件发生的情况是,在使用 setCentralWidget()
之前,即删除父级,它是从父级更改的:
myLayout=QtWidgets.QVBoxLayout() # some parent
myLayout.addWidget(self.btn) # a new parent is established
[...]
self.setCentralWidget(wid) # elimination of the old parent
最后我将使用以下代码解释一个随机示例:
class window25(QtWidgets.QMainWindow):
counter = 0
def __init__(self):
try:
super(window25,self).__init__()
self.lineedit=QtWidgets.QLineEdit()
self.lineedit.setObjectName("QLineEdit")
self.checkbox=QtWidgets.QCheckBox()
self.checkbox.setObjectName("QCheckBox")
self.optBox=QtWidgets.QRadioButton()
self.optBox.setObjectName("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:
print("\ncall guichange")
wid = QtWidgets.QWidget()
wid.setObjectName("wid-{}".format(self.counter))
myLayout=QtWidgets.QVBoxLayout()
myLayout.addWidget(self.btn)
tmp = random.choice([self.lineedit,self.checkbox,self.optBox])
myLayout.addWidget(tmp)
wid.setLayout(myLayout)
wid.destroyed.connect(lambda obj: print("delete: ",obj.objectName()))
tmp.destroyed.connect(lambda obj: print("delete: ",obj.objectName()))
self.setCentralWidget(wid)
print("add: {} parent: {}".format(tmp.objectName(),tmp.parent().objectName()))
self.counter += 1
except Exception as E:
print(E)
解释:
call guichange
QLineEdit # tmp is QLineEdit
add: QLineEdit parent: wid-0 # set to wid-0 as the parent of QLineEdit
call guichange
QLineEdit # tmp is QLineEdit
add: QLineEdit parent: wid-1 # set to wid-1 as new parent of QLineEdit
delete: wid-0 # delete old parent
call guichange
QRadioButton # tmp is QRadioButton
add: QRadioButton parent: wid-2 # set to wid-2 as the parent of QRadioButton
delete: wid-1 # delete old parent
delete: QLineEdit # message printed by the lambda function
delete: QLineEdit # indicating that QLineEdit has been deleted
call guichange
wrapped C/C++ object of type QLineEdit has been deleted # you want to use QLineEdit
# but it had been removed
# previously causing
# that error message
如果你想交换小部件,适当的选项是 QStackedWidget
,如下所示:
class window25(QtWidgets.QMainWindow):
def __init__(self):
super(window25, self).__init__()
self.lineedit = QtWidgets.QLineEdit()
self.checkbox = QtWidgets.QCheckBox()
self.optBox = QtWidgets.QRadioButton()
self.btn = QtWidgets.QPushButton("press me")
wid = QtWidgets.QWidget()
myLayout=QtWidgets.QVBoxLayout()
self.stacked = QtWidgets.QStackedWidget()
self.stacked.addWidget(self.lineedit)
self.stacked.addWidget(self.checkbox)
self.stacked.addWidget(self.optBox)
wid.setLayout(myLayout)
myLayout.addWidget(self.btn)
myLayout.addWidget(self.stacked)
self.setCentralWidget(wid)
self.guichange()
self.btn.clicked.connect(self.guichange)
def guichange(self):
widget = random.choice([self.lineedit,self.checkbox,self.optBox])
self.stacked.setCurrentWidget(widget)
if __name__ == '__main__':
app=QtWidgets.QApplication(sys.argv)
ex=window25()
ex.show()
sys.exit(app.exec_())
关于python - QWidget 类型的包装的 c/c++ 对象已被删除,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48125641/