最近在研究用PyQt写Maya插件的界面,遇到不少的疑难杂症,在这里汇总一下,便于日后查询。
与Maya界面融合
首先最主要的目标是想让PyQt写好的界面与Maya完美融合,不会在操作Maya界面的时候把我们自己的窗口压到后面,而网上传统的方法便是使用OpenMayaUI
库以及shiboken2
库中的wrapInstance
方法,将我们的窗口parent到已经存在的Maya窗口中。
官网的Maya开发人员帮助中也给了以下代码示例:
from maya import OpenMayaUI as omui
from PySide2.QtCore import *
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2 import __version__
from shiboken2 import wrapInstance
mayaMainWindowPtr = omui.MQtUtil.mainWindow()
mayaMainWindow= wrapInstance(long(mayaMainWindowPtr), QWidget)
# WORKS: Widget is fine
hello = QLabel("Hello, World", parent=mayaMainWindow)
hello.setObjectName('MyLabel')
hello.setWindowFlags(Qt.Window) # Make this widget a standalone window even though it is parented
hello.show()
hello = None # the "hello" widget is parented, so it will not be destroyed.
# BROKEN: Widget is destroyed
hello = QLabel("Hello, World", parent=None)
hello.setObjectName('MyLabel')
hello.show()
hello = None # the "hello" widget is not parented, so it will be destroyed.
代码中对比了
parent = mayaMainWindow
和parent = None
两种情况,后者在使用show()方法后窗口会由于Python的GC机制在创建后瞬间消失,但前者由于parent到了Maya的主窗口中,就会由Maya来维持其生命周期。另外,此时在操作Maya界面的时候,我们的窗口也会一直保持置顶不会被挡住。
Dock窗口
为了让我们的窗口能够dock在Maya的UI中,网上常见的方法是结合上面的wrapInstance
方法,再通过内置库的cmds.workspaceControl
来实现。(注:Maya2017之前的版本为 cmds.dockControl
)
例如Dhruv Govil大神的Python For Maya: Artist Friendly Programming教程中的一个案例就是如此:
def getDock(name='LightingManagerDock'):
# Delete existing window first
deleteDock(name)
ctrl = pm.workspaceControl(name,dockToMainWindow=('right',1),label="Lighting Manager")
qtCtrl = omui.MQtUtil.findControl(ctrl)
ptr = wrapInstance(long(qtCtrl),QtWidgets.QWidget)
return ptr
def deleteDock(name='LightingManagerDock'):
if pm.workspaceControl(name,query=True,exists=True) :
pm.deleteUI(