0

I have some problems with PySide and it's internal cleanup process. It seems that my PySide objects are deleted before I really use them. The following example is maybe not the best one, but it was easiest one to simply and reproduce the same error. The only difference is, that in the Application I use, the API gives me a wrapInstance function to get the QMainWindow (each time with a new ID). But the Error is the same.

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_())

The result:

## 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.

How do I get rid of the cleanup process from PySide? Or do I have to define the QObjects in a different way to leave them alive?

If you change the PySide import to from PyQt4 import QtGui you will see that it works fine with PyQt.

MagSec
  • 346
  • 4
  • 17

1 Answers1

1

After a bit more research I found the answer here. So PySide is not taking much care of parenting the objects if the object creation is done in the "pythonic" way. The best thing to do, is to define the object with a parent and then add the object to it's parent.

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)

Now it works like expected and the objects won't be put into the garbage collection for the cleanup. The QT cObject is now taking care of it's relation and not PySide and hold's the object alive. But it would be nice if this feature will be implemented in the next update of PySide, because the way to create it now is not very "pythonic"

Community
  • 1
  • 1
MagSec
  • 346
  • 4
  • 17
  • FYI PySide doesn't see much development these days. They do have a bug tracker so you could post the issue there. If you want better long term support, I would suggest moving to PyQt (though the free license is slightly more restrictive for commercial applications) – three_pineapples Mar 21 '15 at 01:29
  • @three_pineapples: I have to work with booth, because some application API's only support PySide. I wrote some wrapper libs which automatically imports the right system to work with – MagSec Aug 24 '15 at 11:54