这是由Qt的实现和原理引起的,回顾
documentation
观察:
[...]
QObject在对象树中组织自己。当您创建
QObject与另一个对象作为父对象时,该对象将自动
将其自身添加到父级的子级()列表中。父母拥有所有权
对象的名称;i、 例如,它将在其
析构函数。可以按名称和可选类型查找对象
使用findChild()或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_())