PyQt: RuntimeError: завершенный объект C/С++ удален

Если я запустил этот код:

    #!/usr/local/bin/    python3

import sys 
from PyQt4.QtCore import *
from PyQt4.QtGui import *


class Window(QMainWindow):

    def __init__(self):
        super().__init__()
        self.button1 = QPushButton("1")
        self.button2 = QPushButton("2")
        self.setCentralWidget(self.button1)
        self.button1.clicked.connect(lambda: self.setCentralWidget(self.button2))
        self.button2.clicked.connect(lambda: self.setCentralWidget(self.button1))
        self.show()

if __name__ == '__main__':

    import sys 
    app = QApplication(sys.argv)
    window = Window()
    sys.exit(app.exec_())

... Я получаю этот вывод:

Traceback (most recent call last):
  File "test.py", line 16, in <lambda>
    self.button2.clicked.connect(lambda: self.setCentralWidget(self.button1))
RuntimeError: wrapped C/C++ object of type QPushButton has been deleted

Я не понимаю, почему объект удаляется. Окно должно содержать ссылку на него. Я тщательно изучил эти должности: Понятно, что ошибка "базового объекта C/С++ была удалена" Можно ли запросить QQbject PyQt4, чтобы определить, был ли поврежден исходный экземпляр С++?

Почему кнопка удаляется?

Ответ 1

Этот ответ на этот вопрос встречается здесь: Python PySide (внутренний объект С++ уже удален)

По-видимому, присвоение одного виджета QMainWindow с помощью setCentralWidget, а затем назначение другого виджета с помощью setCentralWidget приведет к удалению скрытого QWidget С++, хотя у меня есть объект, который поддерживает ссылку на него.

Примечание. QMainWindow берет на себя управление указателем виджета и удаляет его в соответствующее время.

Ответ 2

Ответ на мозг прекрасно объясняет проблему. Эта ссылка объясняет подробности более подробно.

Мое решение этой проблемы состояло в том, чтобы установить виджеты в качестве атрибутов объекта (например, просто используя self.label = ... вместо label = ... в ваших методах класса). Возможно, вы захотите сделать то же самое для любых макетов, прикрепленных к виджету.

Таким образом вы создаете копию виджета, чтобы при очистке памяти С++ у вас все еще есть ссылка на виджет.

Надеюсь, что это поможет.

Ответ 3

В другом случае решением было сначала добавить все дочерние объекты в отдельный макет, а в качестве последнего шага добавить макет в родительский макет. То есть:

    l = QGridLayout()
    l.addWidget(QLabel("child1"), 0, 0)
    l.addWidget(QLabel("child2"), 0, 1)
    ...
    parentLayout.addLayout(l)