PySide Error: "Internal C++ object [..] already deleted."; While recursive grab/create QObjects
PySide Error: "Internal C++ object [..] already deleted."; While recursive grab/create QObjects
我在使用 PySide 及其内部清理过程时遇到了一些问题。似乎我的 PySide 对象在我真正使用它们之前就被删除了。下面的示例可能不是最好的示例,但它是最简单的示例,可以简单地重现相同的错误。唯一的区别是,在我使用的应用程序中,API 为我提供了一个 wrapInstance
函数来获取 QMainWindow
(每次都有一个新 ID)。但是错误是一样的。
import sys
from PySide import QtGui
class AnyApplication(QtGui.QMainWindow):
def __init__(self):
super(AnyApplication, self).__init__()
self.initUI()
def initUI(self):
self._menuBar = self.menuBar()
for dummy in ["File","Edit","Help"]:
self._menuBar.addMenu(dummy)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('MenuTest')
class MenuBar(object):
def __init__(self, qMenuBar):
self.menuBar = qMenuBar
def AddMenu(self, name):
result = self.GetMenu(name)
if result: return result
else:
new = self.menuBar.addMenu(name)
print "Created: ",name , new
result = Menu(new, name)
return result
def GetMenu(self, name):
print "\nSearch for: ",name
for action in self.menuBar.actions():
if action.text()==name:
print "Found: ",name , action.menu().actions()
return Menu( action.menu(), name)
return None
class Menu(object):
def __init__(self, menu=None, name=None):
self.menu = menu
self.name = name
def AddMenu(self, name):
# print "Name: ",name
result = self.GetMenu(name)
if result: return result
else:
new = self.menu.addMenu(name)
print "Created: ",name , new
result = Menu(new, name)
return result
def GetMenu(self, name):
print "\nSearch for: ",name
for action in self.menu.actions():
if action.text()==name:
print "Found: ",name , action.menu()
return Menu(action.menu(), name)
return None
if __name__ == '__main__':
# Launch Application
app = QtGui.QApplication(sys.argv)
anyApp = AnyApplication()
anyApp.show()
# Access Application with API
print "\n## 1st ####################"
apiMenu = MenuBar(anyApp.menuBar()).AddMenu("API")
anMenu = apiMenu.AddMenu("Analyse")
print "\n## 2nd ####################"
apiMenu = MenuBar(anyApp.menuBar()).AddMenu("API")
exMenu = apiMenu.AddMenu("Execute")
sys.exit(app.exec_())
结果:
## 1st ####################
Search for: API
Created: API <PySide.QtGui.QMenu object at 0x00000000031E7488>
Search for: Analyse
Created: Analyse <PySide.QtGui.QMenu object at 0x00000000031E7408>
## 2nd ####################
Search for: API
Found: API [<PySide.QtGui.QAction object at 0x00000000031E7588>]
Search for: Execute
Traceback (most recent call last):
File "C:/test/qtMenu.py", line 92, in <module>
exMenu = apiMenu.AddMenu("Execute")
File "C:/test/qtMenu.py", line 61, in AddMenu
result = self.GetMenu(name)
File "C:/test/qtMenu.py", line 71, in GetMenu
for action in self.menu.actions():
RuntimeError: Internal C++ object (PySide.QtGui.QMenu) already deleted.
如何摆脱 PySide 的清理过程?还是我必须以不同的方式定义 QObjects 才能让它们存活?
如果您将 PySide 导入更改为 from PyQt4 import QtGui
,您会发现它可以与 PyQt 一起正常工作。
经过更多研究,我找到了答案 here。
因此,如果对象创建是以 "pythonic" 方式完成的,PySide 不会过多关注对象的父级。最好的办法是用父对象定义对象,然后将对象添加到它的父对象中。
def AddMenu(self, name):
result = self.GetMenu(name)
return result if result else \
Menu( self.menuBar.addMenu( QtGui.QMenu(title=name, parent=self.menuBar) ).menu(), name)
现在它像预期的那样工作,对象不会被放入垃圾回收中进行清理。 QT cObject 现在正在处理它的关系,而不是 PySide 并保持对象处于活动状态。但是如果这个特性能在PySide的下一次更新中实现就好了,因为现在的创建方式不是很"pythonic"
我在使用 PySide 及其内部清理过程时遇到了一些问题。似乎我的 PySide 对象在我真正使用它们之前就被删除了。下面的示例可能不是最好的示例,但它是最简单的示例,可以简单地重现相同的错误。唯一的区别是,在我使用的应用程序中,API 为我提供了一个 wrapInstance
函数来获取 QMainWindow
(每次都有一个新 ID)。但是错误是一样的。
import sys
from PySide import QtGui
class AnyApplication(QtGui.QMainWindow):
def __init__(self):
super(AnyApplication, self).__init__()
self.initUI()
def initUI(self):
self._menuBar = self.menuBar()
for dummy in ["File","Edit","Help"]:
self._menuBar.addMenu(dummy)
self.setGeometry(300, 300, 250, 150)
self.setWindowTitle('MenuTest')
class MenuBar(object):
def __init__(self, qMenuBar):
self.menuBar = qMenuBar
def AddMenu(self, name):
result = self.GetMenu(name)
if result: return result
else:
new = self.menuBar.addMenu(name)
print "Created: ",name , new
result = Menu(new, name)
return result
def GetMenu(self, name):
print "\nSearch for: ",name
for action in self.menuBar.actions():
if action.text()==name:
print "Found: ",name , action.menu().actions()
return Menu( action.menu(), name)
return None
class Menu(object):
def __init__(self, menu=None, name=None):
self.menu = menu
self.name = name
def AddMenu(self, name):
# print "Name: ",name
result = self.GetMenu(name)
if result: return result
else:
new = self.menu.addMenu(name)
print "Created: ",name , new
result = Menu(new, name)
return result
def GetMenu(self, name):
print "\nSearch for: ",name
for action in self.menu.actions():
if action.text()==name:
print "Found: ",name , action.menu()
return Menu(action.menu(), name)
return None
if __name__ == '__main__':
# Launch Application
app = QtGui.QApplication(sys.argv)
anyApp = AnyApplication()
anyApp.show()
# Access Application with API
print "\n## 1st ####################"
apiMenu = MenuBar(anyApp.menuBar()).AddMenu("API")
anMenu = apiMenu.AddMenu("Analyse")
print "\n## 2nd ####################"
apiMenu = MenuBar(anyApp.menuBar()).AddMenu("API")
exMenu = apiMenu.AddMenu("Execute")
sys.exit(app.exec_())
结果:
## 1st ####################
Search for: API
Created: API <PySide.QtGui.QMenu object at 0x00000000031E7488>
Search for: Analyse
Created: Analyse <PySide.QtGui.QMenu object at 0x00000000031E7408>
## 2nd ####################
Search for: API
Found: API [<PySide.QtGui.QAction object at 0x00000000031E7588>]
Search for: Execute
Traceback (most recent call last):
File "C:/test/qtMenu.py", line 92, in <module>
exMenu = apiMenu.AddMenu("Execute")
File "C:/test/qtMenu.py", line 61, in AddMenu
result = self.GetMenu(name)
File "C:/test/qtMenu.py", line 71, in GetMenu
for action in self.menu.actions():
RuntimeError: Internal C++ object (PySide.QtGui.QMenu) already deleted.
如何摆脱 PySide 的清理过程?还是我必须以不同的方式定义 QObjects 才能让它们存活?
如果您将 PySide 导入更改为 from PyQt4 import QtGui
,您会发现它可以与 PyQt 一起正常工作。
经过更多研究,我找到了答案 here。 因此,如果对象创建是以 "pythonic" 方式完成的,PySide 不会过多关注对象的父级。最好的办法是用父对象定义对象,然后将对象添加到它的父对象中。
def AddMenu(self, name):
result = self.GetMenu(name)
return result if result else \
Menu( self.menuBar.addMenu( QtGui.QMenu(title=name, parent=self.menuBar) ).menu(), name)
现在它像预期的那样工作,对象不会被放入垃圾回收中进行清理。 QT cObject 现在正在处理它的关系,而不是 PySide 并保持对象处于活动状态。但是如果这个特性能在PySide的下一次更新中实现就好了,因为现在的创建方式不是很"pythonic"