已删除包装类型为QWidget的c / c ++对象

时间:2018-01-06 08:36:02

标签: python pyqt pyqt5

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次工作)正确")但之后我收到了错误

  

包装的QCheckBox类型的c / c ++对象已被删除

     

QLineEdit类型的包装c / c ++对象已被删除

我无法理解哪个陈述导致了这个错误以及我错误的原因或地点

1 个答案:

答案 0 :(得分:2)

这是由Qt的实施和理念引起的,回顾了观察到的documentation

  

[...]

     

QObjects在对象树中组织自己。当你创建一个   QObject以另一个对象作为父对象,该对象将自动生成   将自己添加到父亲的子()列表中。父母拥有所有权   对象;即,它将自动删除其中的子女   析构函数。您可以按名称查找对象,也可以选择键入   使用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_())