PyQtでは循環参照に注意
Traceback (most recent call last): File "D:\Owner\temp\q.py", line 14, in callback self.setText(v) RuntimeError: underlying C/C++ object has been deleted
PyQtを使った方なら、一度はこのRuntimeErrorに遭遇した事があると思います。
ウィジェットのC++の部分が存在しない時のエラーです。
原因の大半は、ウィジェットのサブクラスで、スーパークラスのコンストラクタを呼び忘れることです。
しかし、循環参照が原因の事もあるようです。
#encoding:shift-jis from __future__ import division, print_function import sys from PyQt4.QtGui import * from PyQt4.QtCore import * class SelfRefWidget(QLineEdit): def __init__(self): QLineEdit.__init__(self) self._spam = self.callback def callback(self, v): self.setText(v) def __del__(self): print("dying", self) class ScrollArea(QScrollArea): signal = pyqtSignal(str) def __init__(self, *a, **kw): QScrollArea.__init__(self, *a, **kw) self.createWidget() def hello(self): self.signal.emit("hello") def createWidget(self): w = SelfRefWidget() self.signal.connect(w.callback) self.setWidget(w) def main(): app = QApplication(sys.argv) w = QWidget() e = ScrollArea() e.createWidget() e.hello() if __name__ == "__main__": main()
このコードを実行すると、"underlying C/C++ object has been deleted"が表示されます。
"e.createWidget()"で、ScrollAreaの中身が新しく作られますが、
そのとき古い中身は、どこからも参照されないので破棄
・・・されるはずなのですが、循環参照があるためすぐには破棄されません。
そのためe.hello()で、古い中身のcallbackも呼ばれます。
しかし、どういうわけかSelfRefWidgetのC++部分は先に削除されているようです。
そのためself.setTextでエラーになります。
循環参照で注意なのが、束縛メソッドです。
メソッドの別名を作るつもりで、
self.setElmId = self.setId
とやってしまうと循環参照が発生してしまいます。