Problem with Custom Shelf Tool Python Window

   932   3   3
User Avatar
Member
180 posts
Joined: Dec. 2011
Offline
I am trying to write a python window that launches when a shelf tool button is pressed. I have been able to launch the window, however it seems that all the references to my widgets break once the window is initialized. Callbacks and anything that happens afterwards result in a “RuntimeError: Internal C++ object (PySide.QtGui.QListWidget) already deleted.” I'm guessing that this has something to do with Houdini's event loop?

I will try to post some example code tomorrow, but I just wanted to post this and see if anyone had any ideas.
User Avatar
Member
180 posts
Joined: Dec. 2011
Offline
So here is the sample code I promised. After further testing it, the problem definitely has to do with parenting the window to Houdini's mainQtWindow. The .ui file that the code is reading in is just a button and a qlineedit inside a horizontal layout. This script is being run via a shelf tool.

import os
from PySide import QtCore
from PySide import QtGui
from PySide import QtUiTools

class TweakedDemo(QtGui.QWidget):
    def __init__(self, parent=None):
        super(TweakedDemo, self).__init__(parent)

        loader = QtUiTools.QUiLoader()
        gui_path = os.path.join(os.getenv('HIP'),'testGui.ui')
        self.gui = loader.load(gui_path)

        self.setGeometry(500, 300, 250, 110)
        self.setWindowTitle('Tweaked Demo')

        button = self.gui.findChild(QtGui.QPushButton, "button")
        self.field = self.gui.findChild(QtGui.QLineEdit, "textField")
        
        self.connect(button, QtCore.SIGNAL('clicked()'), self.changeText)

        vbox = QtGui.QVBoxLayout()
        vbox.addWidget(self.gui)
        self.setLayout(vbox)

    def changeText(self):
        self.field.setText('Hello World')
            
    def closeEvent(self, event):
        self.setParent(None)

dialog = TweakedDemo()
dialog.setParent(hou.ui.mainQtWindow(), QtCore.Qt.Window)
dialog.show()

Just to reiterate, if I click the button on this example I get a
RuntimeError: Internal C++ object (PySide.QtGui.QListWidget) already deleted.
error. Which seems odd since the whole point of parenting the window to Houdini is to avoid references being deleted.

If I get rid of the
dialog.setParent(hou.ui.mainQtWindow(), QtCore.Qt.Window)
line then it runs, but only if the class is defined inside the tool's script window. If I move the class into an external file and then load it as a module, then the window is deleted as soon as it's made. My guess is that this is due to its references being cleaned up since it is not parented to Houdini's Qt session.

Is there a way to work around this?
Edited by NFX - March 29, 2018 13:44:40
User Avatar
Staff
1082 posts
Joined: July 2005
Offline
Hello,

I think I have run into this issue before. It has to do with the lifespan of Python variables and PySide/shiboken deciding what it owns and what it can delete. It's a long explanation but here are a couple of workarounds you can try.

1) Assign the result of hou.ui.mainQtWindow()to a variable that lives past the lifetime of the shelf tool's Python context. For example:
hou.session.mainWindow = hou.ui.mainQtWindow()
dialog.setParent(hou.session.mainWindow, QtCore.Qt.Windows)

2) Alternatively, don't parent to the main window. Instead assign your dialog to a variable that lives past the lifetime of the shelf tool's Python context. For example:
hou.session.dialog = dialog

I hope this helps.

Cheers,
Rob
User Avatar
Member
180 posts
Joined: Dec. 2011
Offline
Both of these solutions work like a charm. I didn't know you could dynamically declare variables in hou.session like this (though in retrospect this totally makes sense). I'll have to remember that trick for the future.
  • Quick Links