Using QT Designer and PySide to create Maya 2014 Editor Windows

As it turns out trying to implement a custom GUI made with an external editor and using Python to interact with them can be quite a pain in Maya 2014.
Not because it is a difficult process, but because there is very little information on how to do it to be found. And if you do find information, there are either missing steps in the process or require a certain amount of prior knowledge. So here is a short overview on how to get a custom UI made with QT designer working in Maya 2014.

Some additional info

Most of the tutorials you find online will try to explain how to implement PyQt for Maya 2014 and tell you it is a requirement to be able to implement GUI’s made with QT Designer. There is also an official autodesk explanation on how to do this:
Autodesk PyQt tutorial

For most people who just want to add some simple and clean layouts to their scripts this will be the first big hurdle and often be the point where they just give up.
You need to download a couple of files, place them in specific locations and then run those scripts. All nice and simple but this is a very annoying and painful configuration where many things often can go wrong. Not only that but you also need a copy of Visual Studio to be able to run these scripts in order to run and compile the plugins.
Instead of all of this trouble we will use PySide instead of PyQt as it comes with Maya 2014 and will not require all of that hassle.
There will be some syntax difference between the two. But some a quick Google search should often help you adjust for example a tutorial script from PyQt to the equivalent PySide code .

Getting your UI into Maya 2014

Creating a GUI

I am not going to go over this step as this is a rather straight forward part of the whole process. Maya 2014 allready comes with a version of QT designer and can be found under the QT folder of your Maya 2014 install.
For more information on how to use QT Designer you can have a look at the official manual: http://qt-project.org/doc/qt-4.8/designer-manual.html

Here is an image of the UI used for the scripts in this tutorial.

Blog_QTDesignerExample_01

When saving this to a .ui file it gives the following result:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Dialog</class>
 <widget class="QDialog" name="Dialog">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>385</width>
    <height>478</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Dialog</string>
  </property>
  <widget class="QDialogButtonBox" name="buttonBox">
   <property name="geometry">
    <rect>
     <x>30</x>
     <y>240</y>
     <width>341</width>
     <height>32</height>
    </rect>
   </property>
   <property name="orientation">
    <enum>Qt::Horizontal</enum>
   </property>
   <property name="standardButtons">
    <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
   </property>
  </widget>
  <widget class="QPushButton" name="pushButton">
   <property name="geometry">
    <rect>
     <x>10</x>
     <y>10</y>
     <width>361</width>
     <height>31</height>
    </rect>
   </property>
   <property name="text">
    <string>PushButton</string>
   </property>
  </widget>
 </widget>
 <resources/>
 <connections>
  <connection>
   <sender>buttonBox</sender>
   <signal>accepted()</signal>
   <receiver>Dialog</receiver>
   <slot>accept()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>248</x>
     <y>254</y>
    </hint>
    <hint type="destinationlabel">
     <x>157</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
  <connection>
   <sender>buttonBox</sender>
   <signal>rejected()</signal>
   <receiver>Dialog</receiver>
   <slot>reject()</slot>
   <hints>
    <hint type="sourcelabel">
     <x>316</x>
     <y>260</y>
    </hint>
    <hint type="destinationlabel">
     <x>286</x>
     <y>274</y>
    </hint>
   </hints>
  </connection>
 </connections>
</ui>

 

Converting the .ui file to a usable .py file

As you can see, the .ui file is nothing more than a xml file describing the different elements of your UI. To be able to use this information inside of Maya we will need to convert this file to a Python script.
To make life easier you can place your .ui file in your Maya script folder. The default location for this is:

“C:\Users\Username\Documents\maya\scripts\”

So in our case the complete file path would be:

“C:\Users\Username\Documents\maya\scripts\makeCube.ui”

This will allow Maya to automatically find your script file once converted.
If you are planning on making multiple editor scripts using multiple GUI files it can be interesting to set them up as module packages, keeping your project clean and organised. You can find an excellent explanation on how to do this at http://www.chadvernon.com/
Here is a small excerpt from that site explaining the core of setting this up.


“To create a package, create a folder in one of you PYTHONPATH directories like your Maya script directory, then create a file called __init__.py inside of that new folder. The __init__.py can be empty. You can then place your modules into that package and import them as follows.

import packageName.moduleName

You can have packages inside of packages.

import cvtools.rigging.createIkLeg as createIkLeg
createIkLeg('L_leg_joint')

Any code you put in the __init__.py file of a package gets executed with the package. For example, in the above sample package hierarchy, I could have code in scripts/cvtools/__init__.py to create a Maya menu when the package is imported.

import cvtools     # creates a Maya menu

 


But for this example we just place the files in our maya scripts folder. The actual conversion can be done by running the following script inside of the Maya script editor (source: Autodesk reference) :

import sys, pprint
from pysideuic import compileUi
pyfile = open("[path to output python file]\makeCube.py", 'w')
compileUi("[path to input ui file]\makeCube.ui", pyfile, False, 4,False)
pyfile.close()

In our case we converted the makeCube.ui file to a makeCube.py file. Giving us the following piece of code. Note how you can see all the elements that were part of our UI neatly defined.

 # -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'C:\Users\Username\Documents\maya\scripts\makeCube.ui'
#
# Created: Tue Nov 25 13:01:27 2014
#      by: pyside-uic 0.2.14 running on PySide 1.1.1
#
# WARNING! All changes made in this file will be lost!

from PySide import QtCore, QtGui

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(385, 478)
        self.buttonBox = QtGui.QDialogButtonBox(Dialog)
        self.buttonBox.setGeometry(QtCore.QRect(30, 240, 341, 32))
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
        self.buttonBox.setStandardButtons(QtGui.QDialogButtonBox.Cancel|QtGui.QDialogButtonBox.Ok)
        self.buttonBox.setObjectName("buttonBox")
        self.pushButton = QtGui.QPushButton(Dialog)
        self.pushButton.setGeometry(QtCore.QRect(10, 10, 361, 31))
        self.pushButton.setObjectName("pushButton")

        self.retranslateUi(Dialog)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("accepted()"), Dialog.accept)
        QtCore.QObject.connect(self.buttonBox, QtCore.SIGNAL("rejected()"), Dialog.reject)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))
        self.pushButton.setText(QtGui.QApplication.translate("Dialog", "PushButton", None, QtGui.QApplication.UnicodeUTF8))

Using the custom GUI from within a PySide Script

Almost there!
Now we just need to be able to use our GUI from within a PySide Script as follows:

from PySide import QtCore, QtGui
import makeCube as customUI
from shiboken import wrapInstance
import maya.OpenMayaUI as omui

def maya_main_window():
    main_window_ptr = omui.MQtUtil.mainWindow()
    return wrapInstance(long(main_window_ptr), QtGui.QWidget)

class ControlMainWindow(QtGui.QDialog):

    def __init__(self, parent=None):

        super(ControlMainWindow, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Tool)
        self.ui =  customUI.Ui_Dialog()
        self.ui.setupUi(self)

        self.ui.pushButton.clicked.connect(self.someFunc)

    def someFunc(self):
        print 'Hello {0} !'

myWin = ControlMainWindow(parent=maya_main_window())
myWin.show()

Some points of interest

How do we access the UI script?

import makeCube as customUI

This tells us where we can find our UI script. Using customUI we can then access the different UI elements.
If you used the Module setup that I mentioned earlier you will need to use the correct namespace importing if applicable. For example:

import UItestScripts.makeCube as customUI

How do we assign the UI class?

self.ui =  customUI.Ui_Dialog()

Using the customUI alias we can access the class that was defined in the makeCube file. To know what class you should use just have a look at the converted .ui file. In this case:

from PySide import QtCore, QtGui

class Ui_Dialog(object):

Initializing the UI

 self.ui.setupUi(self)

After setting up what ui we will be using we call the setupUI function.
Notice how this function was also present in the converted .ui script.

How do we use our UI elements?

self.ui.pushButton.clicked.connect(self.someFunc)

This piece of code will determine what will happen when you the “clicked” event gets called on the button with the name “pushButton”.
Bellow that we have defined the function to which we are referring.

def someFunc(self):
        print 'Hoozah a working GUI!'

In this case, whenever someone presses the “pushButton” button the console will print the defined text.

Closing words

I hope that this tutorial will be of use to some people. I am not a Maya user myself and this tutorial is the result of me trying to help a friend to get all of this to work. It took us multiple hours and different attempts to find a fully working solution. Going over multiple tutorials and solutions, each either with errors, legacy code, crucial parts missing, no explanation on how to perform certain steps or what you are actually doing.
So therefore this complete step by step overview of how we got a QT designer GUI to work inside of Autodesk’s Maya 2014 using PySide.

Warning: count(): Parameter must be an array or an object that implements Countable in /customers/4/5/d/brechtos.com/httpd.www/wp-includes/class-wp-comment-query.php on line 405

18 Responses

  1. Hi Brecht,

    Thank you so much for this, was as you say pulling my hair out trying to get a Qt interface to work. Was just about to give up and go back to hand Coding a Mel one.

    thanks again.

  2. This was really helpful!!!! Thanks!

    One issue I did have though was the fact that I didn’t use a Dialog, and instead used a MainWindow in the QT Designer. Because of that… I had to change the following lines:

    class ControlMainWindow(QtGui.QMainWindow):

    …and…

    self.ui = customUI.Ui_MainWindow()

  3. thanks a lot!!!!!
    finally a complete explained tutorial. You saved me! I spent 2 days trying to figure out this. As you said, plenty of incomplete tutorials out there. This one is perfect

  4. Thank you so much for this tutorial. I had no idea how to use my converted UI file and learned so much from this post. Thanks again!

        1. Not sure what you mean with this. As far as I know, in order to make use of the designer qt file in maya you need to convert it.
          The qt file itself is just a xml file generated by qt designer based on your design made with the visual editor.

  5. 36: unbound method setupUi() must be called with Ui_Form instance as first argument (got ControlMainWindow instance instead)

    i am faceing this error can you suggest a solution

    1. Make sure your indentation is correct and you are calling the methods from the correct locations is the first thing that comes to mind. (The indentation is actually an important part that needs to be correct with this language…)
      I no longer have access to Maya 2014 so unfortunately I can’t help much beyond this :/
      Hope that that fixes your problem.

  6. Pingback: Cialis pills

Leave a Reply