QtDesigner and Maya layouts

I´ve got started using PySide and Qt Designer and so far I’ve written a few PySide/Qt scripts from scratch, and compiled a test UI made in Qt Designer from inside Maya.
Now I wonder how you deal with controls and layouts that are Maya-only. For example, if I want to have several frameLayouts in my UI, and create the contents of these layouts in Qt Designer, how would I accomplish that?
The “Qframe” container in Qt Designer seems to be something completely different from what it is in Maya (not sure what it’s used for really as it doesn’t seem to have a lot of stuff in the property editor).

this should help.

http://justinfx.com/2011/11/20/mixing-pyqt4-widgets-and-maya-ui-objects/

you can’t really mix maya’s layouts with Qt’s layouts. Qt doesn’t have a frame layout equivalent. You can however, create your own widgets from scratch, and control how they look. I made my own “framelayout” widget and looks indistinguishable from Maya’s (although I haven’t updated it to match 2016s new look).

Also, I rarely use Qt Designer, preferring to do everything in code. I use QtDesigner to test layouts until I am happy, then code it all up myself. It is possible to compile your own widgets so they show up in Qt Designer, but it’s a bit of a hassle.

Doing everything in code means you can create a specialized super-widget that has a mini-layout inside, this makes it really easy to populate GUIs that display the same collection of data for multiple objects very easy. You don’t have to mange creating dozens of checkboxs for example, you just add your super-widget and it manages all the checkboxes for you.

one more thing, my qt implementation of the framelayout widget means I can make a standalone UI outside maya that also has that frameLayout look and functionality.

Its all qt, you can certain grab and re-parent ui elements created with cmds, however you’re almost certain to use them as is. I’ve been able to embed an outliner in my own ui, however you’re pretty much left with it in that state and can’t interact with it too much. No signal connections, etc. However as rgkovach said, you’re now bound to using it in maya only.

I would disagree with rgkovach on the use of designer. I use it with any non-trivial UI. I can get it things to look exactly how i like without writing 500 lines of qt. If its a small simple dialog or widget, then i’ll do it in code.

ha, I actually do the opposite of TheMaxx… if the UI is complicated I do all in code, if it simple, then i’ll use qtDesigner :slight_smile:

I’ve found in production that building a nice UI takes a crap ton of time so I create heavy UI’s in Qt, compile them then have my UI class inherit the QT UI class. I also include the dockable stuff in the class as well. For example:

class MyToolUI(MayaQWidgetDockableMixin, QtGui.QDialog, Ui_compliledQtDialog):
    def __init__(self, parent=getMayaWindow()):
        super(MyToolUI, self).__init__(parent=parent)

I’ve found it pretty flexible to quickly iterate on a UI, run my pyside-uic to compile it and not having to parse a bunch of code to tweak a layout is a big time saver. This has been my workflow. I’m sure not for everyone.

As far as mixing Maya UI with QT I kind of tweaked Nathan’s bit of code for converting maya stuff into qt instances.

def convertToQt(mayaName, objectType):
    """
    Given the name of a Maya UI element of any type, return the corresponding QT Type object.
    """
    ptr = OpenMayaUI.MQtUtil.findControl(mayaName)
    if ptr is None:
        ptr = OpenMayaUI.MQtUtil.findLayout(mayaName)
        if ptr is None:
            ptr = OpenMayaUI.MQtUtil.findMenuItem(mayaName)
    if ptr is not None:
        return wrapInstance(long(ptr), objectType)

I believe he and the return object type as a QObject which was too abstract for my needs and this way I can pass in an explicit QObject type.
Lets say I defined a QVBoxLayout in QT called myLayout.


....
#Create a maya frame layout
frame= cmds.frameLayout()

# add a couple of maya buttons
button1 = cmds.button()
button2 = cmds.button()

# Convert the layout to a qt widget
qtLayout = convertToQt(frame, QtGui.QWidget)

# add this widget to myLayout
myLayout.addWidget(qtLayout)
cmds.setParent('..')

I use this convertToQt quite a bit. Especially on buttons and such so I can change hover states through stylesheets.
-Sean

How come PySide is shipped with Maya but sip is not?
This pretty much kills the idea of creating PySide UI’s for tools you want to distribute on the net. The end-user shouldn’t have to install custom python packages (sip) on their own imo.
Yes you can still make UI’s but any use of pointers would require the sip package, correct?

I must confess that I feel less motivated to work with Qt Designer now seeing all the hassle with the Maya ui objects. I don’t write that many UI’s so I might as well just code it by hand.

[QUOTE=Nightshade;28582]How come PySide is shipped with Maya but sip is not?
This pretty much kills the idea of creating PySide UI’s for tools you want to distribute on the net. The end-user shouldn’t have to install custom python packages (sip) on their own imo.
Yes you can still make UI’s but any use of pointers would require the sip package, correct?

I must confess that I feel less motivated to work with Qt Designer now seeing all the hassle with the Maya ui objects. I don’t write that many UI’s so I might as well just code it by hand.[/QUOTE]

Because PySide uses shiboken, not sip which is used by PyQt instead.

I’m not sure i follow. Basically you do the ui work in designer and save out a .ui file. At this point you can use pyside or pyqt to convert it to essentially a python class with all the qt stuff done for you. Some folks will save that to file and just keep the .py file around, others can use the same process to compile at runtime. Either way, it’s not sip/shiboken bound at all. in fact, neither of those libs is even involved in that process.

To make your ui’s package independent, just do a try import block. The only things you’ll really need to looks out for is using QVariant in pyqt and QtCore.Signal.

Hey Guys,
I wanted to show a practical example of how mixing PySide with Maya UI objects.
For example, I really like some of the conveniences of the scriptTable (mostly the filtering functionality) but formatting the headers with your layout is impossible (well next to impossible).

Straight from the docs:

import maya.cmds as cmds

def edit_cell(row, column, value):
    return 1

window = cmds.window(widthHeight=(400, 300))
form = cmds.formLayout()
table = cmds.scriptTable(rows=4, columns=2, label=[(1,"Column 1"), (2,"Column 2")], cellChangedCmd=edit_cell)

addButton = cmds.button(label="Add Row",command="cmds.scriptTable(table, edit=True,insertRow=1)")
deleteButton = cmds.button(label="Delete Row",command="cmds.scriptTable(table, edit=True,deleteRow=1)")

cmds.formLayout(form, edit=True, attachForm=[(table, 'top', 0), (table, 'left', 0), (table, 'right', 0), (addButton, 'left', 0), (addButton, 'bottom', 0), (deleteButton, 'bottom', 0), (deleteButton, 'right', 0)], attachControl=(table, 'bottom', 0, addButton), attachNone=[(addButton, 'top'),(deleteButton, 'top')],  attachPosition=[(addButton, 'right', 0, 50), (deleteButton, 'left', 0, 50)] )

cmds.showWindow( window )

# Set and query cells
cmds.scriptTable(table, cellIndex=(1,1), edit=True, cellValue="MyValue")

You run this and the last column does not stretch with the layout. Kind of annoying.

Few minor tweaks:

import maya.cmds as cmds
import maya.OpenMayaUI as OpenMayaUI
from shiboken import wrapInstance
from PySide import QtGui

def edit_cell(row, column, value):
    return 1

window = cmds.window(widthHeight=(400, 300))
form = cmds.formLayout()
table = cmds.scriptTable(rows=4, columns=2, label=[(1,"Column 1"), (2,"Column 2")], cellChangedCmd=edit_cell)

addButton = cmds.button(label="Add Row",command="cmds.scriptTable(table, edit=True,insertRow=1)")
deleteButton = cmds.button(label="Delete Row",command="cmds.scriptTable(table, edit=True,deleteRow=1)")

cmds.formLayout(form, edit=True, attachForm=[(table, 'top', 0), (table, 'left', 0), (table, 'right', 0), (addButton, 'left', 0), (addButton, 'bottom', 0), (deleteButton, 'bottom', 0), (deleteButton, 'right', 0)], attachControl=(table, 'bottom', 0, addButton), attachNone=[(addButton, 'top'),(deleteButton, 'top')],  attachPosition=[(addButton, 'right', 0, 50), (deleteButton, 'left', 0, 50)] )

cmds.scriptTable(table, cellIndex=(1,1), edit=True, cellValue="MyValue")

# Find the maya control
ptr = OpenMayaUI.MQtUtil.findControl(table)

#Convert to a QTableWidget
qtTable = wrapInstance(long(ptr), QtGui.QTableWidget)

#Get the headers
header = qtTable.horizontalHeader()

#Make the last header stretch
header.setStretchLastSection(True)

cmds.showWindow( window )

A bit off topic but just wanted to share.
Cheers,
-Sean