Skip to content

Instantly share code, notes, and snippets.

@liorbenhorin
Created December 1, 2017 15:04
Show Gist options
  • Star 29 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save liorbenhorin/69da10ec6f22c6d7b92deefdb4a4f475 to your computer and use it in GitHub Desktop.
Save liorbenhorin/69da10ec6f22c6d7b92deefdb4a4f475 to your computer and use it in GitHub Desktop.
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
Copy link

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
Copy link

daGonen commented Jan 6, 2018

Sachtein

@Nixellion
Copy link

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.

Copy link

ghost 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
Copy link

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

@prsfx
Copy link

prsfx commented Sep 7, 2019

I test this version. And which more better. Right now I need to configure my old window setup.
Thank you for this.

@LucyDimitri
Copy link

Hi,
Thanks for your script !!
Can you help me modify the code to load a Ui file rather than create the interface directly in this code?
Or maybe I can convert my Ui to Py and load it ?

thank you,

@staticnotdynamic
Copy link

Hi,
Thanks for your script !!
Can you help me modify the code to load a Ui file rather than create the interface directly in this code?
Or maybe I can convert my Ui to Py and load it ?

thank you,

It should be straightforward in python, see loadUi
You could also take a look at the previous version of this script. It loaded and parsed .ui files here

@prsfx
Copy link

prsfx commented Dec 24, 2019

Hi,
Thanks for your script !!
Can you help me modify the code to load a Ui file rather than create the interface directly in this code?
Or maybe I can convert my Ui to Py and load it ?

thank you,

If you want to convert *.ui file. You need to use pyuic in console/terminal.

There's 2 type of python bind as I remembered, PyQt and PySide

Maya used PySide2. So in your folder that contain *.ui file right click and use "cmd here"
or..
Open cmd/terminal change directory to your folder then type some command
or...
You can type cmd in folder direction, press enter then type:

#for PyQt5, use:
pyuic5 -x yourUiFilename.ui -o yourUiFileConvertName.py

#if you want to use PySide2:
pyside2-uic -x yourUiFilename.ui -o yourUiFileConvertName.py

So if there's no error in your command you will see *.py extension file inside your folder.

If you don't want to confused yourself to pure PyQt/PySide ui build and just want to build from existing *.ui file and focus on tool development try this https://github.com/prsfx/MayaDockTool

I believed this method way more faster to develope tool. Build HUGE interface is pain in the ass.
If you still confused, I don't know what you want to do with your tool.

Good luck.

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