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 tool then drag it in place to dock it, they will ALL show up when I right-click on Maya's window. How do I properly clean these up when the tool closes?
I already tried cmds.deleteUI
, QObject.deleteLater()
and at best I can only clear the tool's contents, but it will still exist in Maya. Here's an example of what I have so far:
from shiboken import wrapInstance
from PySide import QtGui, QtCore
from maya import OpenMayaUI as OpenMayaUI
from maya.app.general.mayaMixin import MayaQWidgetDockableMixin
class Window(MayaQWidgetDockableMixin, QtGui.QWidget):
def __init__(self, parent = None):
super(self.__class__, self).__init__(parent = parent)
mayaMainWindowPtr = OpenMayaUI.MQtUtil.mainWindow()
self.mayaMainWindow = wrapInstance(long(mayaMainWindowPtr), QtGui.QWidget)
self.setWindowFlags(QtCore.Qt.Window)
if cmds.window('myTool', q = True, ex = True):
cmds.deleteUI('myTool')
self.setObjectName('myTool')
self.setWindowTitle('My tool')
self.resize(200, 200)
self.myButton = QtGui.QPushButton('TEMP')
self.mainLayout = QtGui.QVBoxLayout()
self.mainLayout.addWidget(self.myButton)
self.setLayout(self.mainLayout)
def dockCloseEventTriggered(self):
self.deleteLater()
def run(self):
self.show(dockable = True)
myWin = Window()
myWin.run()
SOLUTION:
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!