Making a Picker GUI for Maya with PySide and QtDesigner

hoppsGui.JPG
The Hopps GUI in Maya 2016.5

The past few weeks have gone into the development of a new picker tool for a character rig I’m finishing up. The UI was designed in the amazing QtDesigner and all the Maya integration was done using PySide (PySide 1 that is).

QT Designer stuff:

The whole design is a QMainWindow widget, and the tabs come from the behavior of two QTabWidget objects.

  1. Do a png playblast of your character in the A or T pose you want them in. You want a nice obvious silhouette to make it easier to place the controls.
  2. Take that png into your ui file in QtDesigner and add it as the pixmap to a QLabel widget. This QLabel should be the backmost object in your design.
  3. In your python code (we’ll get to that later) you’ll have to re-connect the pixmap with the correct file path, but we will do this in QtDesigner so that we have a reference for placing our controls.
  4. Make sure you have “scaledContents” enabled.

Now it was just a matter of adding buttons.

  1. Add a button widget
  2. Give it an original objectName
  3. You can color it if you wish with the styleSheet property.
    1. background-color: rgb(80, 255, 73);\ncolor: rgb(0, 0, 0);
      1. ^^ that’s an example of the style sheet my green buttons shared. The background-color flag controls the color of the button and the color flag controls the color of the text.

The other widgets were pretty straightforward if you’ve ever done any PySide or PyQt coding. Besides QPushButton I used QLineEdit for the Namespace input and QComboBox for the dropdown menu.

qtDesigner

Integrating with Maya:

This was one of the hardest parts of the project to figure out. A whole lot of props goes to internet heroes like Brian Kortbus who are kind enough to post information and code relating to QtDesigner and PySide integration. Here’s the problem:

QtDesigner gives you a .ui file which Maya doesn’t know how to deal with. Maya DOES however have integration with PySide, which can take ui files and convert them into objects that Python can deal with. Basically, if you’ve ever hand-coded a UI in PySide, the following code allows you to take your nice ui you made in QtDesigner and make it into something that can be easily integrated with Maya (2016.5 or below):

So for example, if we had a QPushButton object in QtDesigner named addCube_btn, line 56 would then connect its “clicked” slot to the function “someFunction”. It’s really that easy for every other button, it just takes a lot of manual connection. The nice thing is that the names for my controls won’t change much between characters so the UI will be pretty re-usable.

I said earlier we had to do something with the pixmap on our QLabel widget. This is what I did:

self.MainWindowUI.bgdImage_label.setPixmap(QtGui.QPixmap(SCRIPT_LOC + "\\hoppsGuiBody.png"))

If I didn’t do this then the background image wouldn’t show up since the folder that QtDesigner makes the image point to by default isn’t at all what you want. I know there’s a whole resource system and all in QtDesigner but considering this project needed only one pixmap I didn’t really find it necessary to get that deep into learning how to do that. Maybe later.

Connecting Widgets:

Now, there are a few things to note with selecting controls. First of all, you can’t just pass it a control like “L_shoulderFK_CTRL” because you don’t know if the rig was referenced or not. That’s where the Namespace comes in. Instead of just directly selecting my control, I made the buttons call a function that concatenates the defined namespace onto the control. In other words: cmds.select(self.namespace + ctrl, add=1) where self.namespace is defined as self.MainWindowUI.namespaceTxt.text() in another function.

So that takes care of the selection issue. With that same code, we’re able to do things like select the entire body, reset the selection, key selection…

I think I posted this before but the code I use for a smart reset of an object’s attributes is:

sel = cmds.ls(sl=1)
for obj in sel:
    keyable = cmds.listAttr(obj, keyable=1, unlocked=1, settable=1)
    for attr in keyable:
        default = cmds.attributeQuery(attr, node=obj, listDefault=1)
        if cmds.getAttr(obj + "." + attr, settable=1) != 0:
            cmds.setAttr(obj + "." + attr, default[0])

That’s it for this post. I’ll make another post where I talk about how I tackled the fun problems of pose flipping/mirroring and IK-FK and FK-IK snapping.

A thing to note is that this is all written in PySide1, and Maya 2017 and up uses the newer version PySide2. Unfortunately, just changing the input line doesn’t fix the integration (yes I tried it) but I have seen some posts about the problem that try to fix it. So yes, this rig is for Maya 2016.5.

~ Ben Morgan

 

Advertisements
Image

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s