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

标签 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 次工作正确”)但在那之后我得到了一个错误

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/

相关文章:

python - 添加的 QMenu 未触发 QAction

python - QFrame 内的 Vlc 播放器

Python。如何在Python中从列表中删除零

python - 为什么 pandas Series.str 将数字转换为 NaN?

python - 模板标签值中的 Django 非 ASCII 字符

python - 如何从任意长度的 Python3 字符串数组构建 QML ListElements

javascript - 未捕获的语法错误 : Unexpected end of JSON input error when i try to take data from mysql

python - 如何使用 QAbstractTableModel 模型控制其他小部件?

python - 如何将通知编号添加到按钮图标?

python-3.x - PyQt5 QWebEngineView 无法正常工作