代码之家  ›  专栏  ›  技术社区  ›  Nimish Bansal

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

  •  3
  • Nimish Bansal  · 技术社区  · 7 年前
    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可以更改窗口,但我尝试了其他方法,即按下按钮随机更改主窗口中心小部件。几次成功后(即按下按钮3,4次可正常工作),但之后我出现了一个错误

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

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

    我无法理解是哪个陈述导致了这个错误,以及我错在哪里或为什么错

    1 回复  |  直到 7 年前
        1
  •  4
  •   Community Mohan Dere    5 年前

    这是由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_())