Dockable window in Maya with PySide clean up

匿名 (未验证) 提交于 2019-12-03 08:28:06

问题:

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!

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!