Instantly share code, notes, and snippets.

Embed
What would you like to do?
Simple way to Docking Qt widgets to Maya 2017+
'''
Template class for docking a Qt widget to maya 2017+.
Author: Lior ben horin
12-1-2017
'''
import weakref
import maya.cmds as cmds
import maya.OpenMayaUI as omui
from shiboken2 import wrapInstance
from Qt import QtGui, QtWidgets, QtCore # https://github.com/mottosso/Qt.py by Marcus Ottosson
def dock_window(dialog_class):
try:
cmds.deleteUI(dialog_class.CONTROL_NAME)
logger.info('removed workspace {}'.format(dialog_class.CONTROL_NAME))
except:
pass
# building the workspace control with maya.cmds
main_control = cmds.workspaceControl(dialog_class.CONTROL_NAME, ttc=["AttributeEditor", -1],iw=300, mw=True, wp='preferred', label = dialog_class.DOCK_LABEL_NAME)
# now lets get a C++ pointer to it using OpenMaya
control_widget = omui.MQtUtil.findControl(dialog_class.CONTROL_NAME)
# conver the C++ pointer to Qt object we can use
control_wrap = wrapInstance(long(control_widget), QtWidgets.QWidget)
# control_wrap is the widget of the docking window and now we can start working with it:
control_wrap.setAttribute(QtCore.Qt.WA_DeleteOnClose)
win = dialog_class(control_wrap)
# after maya is ready we should restore the window since it may not be visible
cmds.evalDeferred(lambda *args: cmds.workspaceControl(main_control, e=True, rs=True))
# will return the class of the dock content.
return win.run()
class MyDockingUI(QtWidgets.QWidget):
instances = list()
CONTROL_NAME = 'my_workspcae_control'
DOCK_LABEL_NAME = 'my workspcae control'
def __init__(self, parent=None):
super(MyDockingUI, self).__init__(parent)
# let's keep track of our docks so we only have one at a time.
MyDockingUI.delete_instances()
self.__class__.instances.append(weakref.proxy(self))
self.window_name = self.CONTROL_NAME
self.ui = parent
self.main_layout = parent.layout()
self.main_layout.setContentsMargins(2, 2, 2, 2)
# here we can start coding our UI
self.my_label = QtWidgets.QLabel('hello world!')
self.main_layout.addWidget(self.my_label)
@staticmethod
def delete_instances():
for ins in MyDockingUI.instances:
logger.info('Delete {}'.format(ins))
try:
ins.setParent(None)
ins.deleteLater()
except:
# ignore the fact that the actual parent has already been deleted by Maya...
pass
MyDockingUI.instances.remove(ins)
del ins
def run(self):
return self
# this is where we call the window
my_dock = dock_window(MyDockingUI)
@griffinanimator

This comment has been minimized.

griffinanimator commented Dec 7, 2017

This is good stuff. I'm trying to use this to build a base class that has a docking method so I can inherit in other UI classes. It mostly works, except the main_layout doesn't display. I will post more if I get a solution.

@daGonen

This comment has been minimized.

daGonen commented Jan 6, 2018

Sachtein

@Nixellion

This comment has been minimized.

Nixellion commented Feb 9, 2018

Hi, @liorbenhorinliorbenhorin !

This is great boilerplate. I succesfully repurposed it as a base module and class, which I can use in different windows. Tested in Maya 2017, worked great. I will be performing tests of it in different Maya versions.

But I'm writing because of a small problem I found. It seems that this window does not show the menuBar, when I use self.setMenuBar(manuBarVar) command. Is there a solution to this?

Thanks.

@ombracg

This comment has been minimized.

ombracg commented Feb 22, 2018

Hi all this is a good stuff but I have a problem. The dock windows can show only one time , if I run the code it delete instance and cannot pop up again.
Any solutions please?
Thanks

@CraigLaMorte

This comment has been minimized.

CraigLaMorte commented Mar 20, 2018

where do you set self.setSizeGripEnabled(False)? This new way won't let me set those attributes to my window anymore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment