Dockable window in Maya with PySide clean up

后端 未结 1 1086
我寻月下人不归
我寻月下人不归 2020-12-29 16:49

I created a tool that is able to dock in Maya\'s main ui, but I can\'t figure out a way to clean it up once it closes. The problem is if I create multiple instances of the t

相关标签:
1条回答
  • 2020-12-29 17:18

    After digging around mayaMixin.py I managed to get a working solution with the behavior I'm after! The idea is that you need to dig through Maya's main window and delete any instances of it there.

    The example below will cleanly delete any instances once the window is closed or a new instance is created. It doesn't matter if it's docked or floating, it seems to work ok. You could always tweak the behavior too if you don't want it to delete if it's closed while being docked. I left many comments in the code as there was a lot of "gotchas".

    from shiboken import wrapInstance
    from PySide import QtGui, QtCore
    from maya import OpenMayaUI as OpenMayaUI
    from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
    from maya.OpenMayaUI import MQtUtil
    
    class MyWindow(MayaQWidgetDockableMixin, QtGui.QDialog):
        toolName = 'myToolWidget'
    
        def __init__(self, parent = None):
            # Delete any previous instances that is detected. Do this before parenting self to main window!
            self.deleteInstances()
    
            super(self.__class__, self).__init__(parent = parent)
            mayaMainWindowPtr = OpenMayaUI.MQtUtil.mainWindow() 
            self.mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QtGui.QMainWindow)
            self.setObjectName(self.__class__.toolName) # Make this unique enough if using it to clear previous instance!
    
            # Setup window's properties
            self.setWindowFlags(QtCore.Qt.Window)
            self.setWindowTitle('My tool')
            self.resize(200, 200)
    
            # Create a button and stuff it in a layout
            self.myButton = QtGui.QPushButton('My awesome button!!')
            self.mainLayout = QtGui.QVBoxLayout()
            self.mainLayout.addWidget(self.myButton)
            self.setLayout(self.mainLayout)
    
        # If it's floating or docked, this will run and delete it self when it closes.
        # You can choose not to delete it here so that you can still re-open it through the right-click menu, but do disable any callbacks/timers that will eat memory
        def dockCloseEventTriggered(self):
            self.deleteInstances()
    
        # Delete any instances of this class
        def deleteInstances(self):
            mayaMainWindowPtr = OpenMayaUI.MQtUtil.mainWindow() 
            mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QtGui.QMainWindow) # Important that it's QMainWindow, and not QWidget/QDialog
    
            # Go through main window's children to find any previous instances
            for obj in mayaMainWindow.children():
                if type( obj ) == maya.app.general.mayaMixin.MayaQDockWidget:
                    #if obj.widget().__class__ == self.__class__: # Alternatively we can check with this, but it will fail if we re-evaluate the class
                    if obj.widget().objectName() == self.__class__.toolName: # Compare object names
                        # If they share the same name then remove it
                        print 'Deleting instance {0}'.format(obj)
                        mayaMainWindow.removeDockWidget(obj) # This will remove from right-click menu, but won't actually delete it! ( still under mainWindow.children() )
                        # Delete it for good
                        obj.setParent(None)
                        obj.deleteLater()        
    
        # Show window with docking ability
        def run(self):
            self.show(dockable = True)
    
    myWin = MyWindow()
    myWin.run()
    

    With this it's no longer polluting Maya's environment anymore. Hope it helps!

    0 讨论(0)
提交回复
热议问题