简体   繁体   English

使用PySide清理Maya中的可停靠窗口

[英]Dockable window in Maya with PySide clean up

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. 我创建了一个可以停靠在Maya主ui中的工具,但是我想不出一种方法来关闭它。 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. 问题是,如果我创建该工具的多个实例,然后将其拖动到适当位置以将其停靠,则在我右键单击Maya的窗口时,它们将全部显示。 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. 我已经尝试过cmds.deleteUIQObject.deleteLater() ,但充其量我只能清除该工具的内容,但它仍然存在于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()

After digging around mayaMixin.py I managed to get a working solution with the behavior I'm after! 在研究了mayaMixin.py之后,我设法获得了我所追求的行为的有效解决方案! The idea is that you need to dig through Maya's main window and delete any instances of it there. 这个想法是,您需要在Maya的主窗口中进行挖掘,然后删除其中的所有实例。

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. 这样,它不再污染Maya的环境。 Hope it helps! 希望能帮助到你!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM