Problem with add maya widget to Qt layout

600 views
Skip to first unread message

张宇

unread,
Mar 8, 2012, 10:07:31 AM3/8/12
to python_in...@googlegroups.com
I want to add a attrFieldSliderGrp to my Qt window, I create the Qt UI
with QtDesinger, there is another file to load the .ui file, I get the
layout's path in maya with MQtUtil.fullName(), I got it.
The QVBoxLayout's name is "SDK_VL",
When used mc.setParent(layoutName) I get a wrong feedback:
# Error: line 1: setParent: Object
'MayaWindow|SuperFaceJntUIObj|SDK_Layout' not found.
# Traceback (most recent call last):
# File "<maya console>", line 1, in <module>
# File "D:/workflow/MyPys/superFaceJnt.py", line 195, in <module>
# main()
# File "D:/workflow/MyPys/superFaceJnt.py", line 191, in main
# d = MyForm(win)
# File "D:/workflow/MyPys/superFaceJnt.py", line 32, in __init__
# self.addWidget()
# File "D:/workflow/MyPys/superFaceJnt.py", line 40, in addWidget
# mc.setParent(SDK_layout)
# RuntimeError: setParent: Object
'MayaWindow|SuperFaceJntUIObj|SDK_Layout' not found. #
If I print the layout's name, I got:
MayaWindow|SuperFaceJntUIObj|SDK_VL

Here is my code:
import sys
import os

from PyQt4 import QtGui, QtCore, uic
import sip

import maya.cmds as mc
import maya.OpenMayaUI as mui

uifile = os.path.join(currentPath, 'superFaceJnt2.ui')
form_class, base_class = uic.loadUiType(uifile)

global app

class MyForm(form_class, base_class):
def __init__(self, parent, **kwargs):
QtGui.QWidget.__init__(self, parent, **kwargs)
self.setupUi(self)
self.addWidget()

def addWidget(self):
SDK_layout = mui.MQtUtil.fullName(long(sip.unwrapinstance(self.SDK_VL)))
print SDK_layout
mc.setParent(SDK_layout)
#self.bn = mc.button()

def main():
global app
app = QtGui.QApplication.instance()
ptr = mui.MQtUtil.mainWindow()
win = sip.wrapinstance(long(ptr), QtCore.QObject)
d = MyForm(win)
d.show()

main()

I need HELP!!!
--
http://zhangyu.me
http://zhang-yu.appspot.com

Justin Israel

unread,
Mar 8, 2012, 1:55:38 PM3/8/12
to python_in...@googlegroups.com
Hey there,

This issue, as far as I know, relates to something I addressed in one of my maya python training videos (vol 2). When you create a ui in Qt Designer and then have maya generate the actual GUI from it, its doing translations to represent widgets. With that in mind, the exact hierarchy and objects aren't completely 1-to-1 or fully accessible all the time. Some of the widgets translate into maya objects that you can control using the commands module, others are simply not accessible in a normal fashion.

The specific issue I am referring to here is regarding layouts. A layout is one of those objects that you can't fully expect to use with commands module, as it becomes just a generic layout when it translates to maya. The problem I have seen is when you have a layout inside another layout, which is perfectly valid in Qt. Maya will do some things differently during translation, and actually give you issues if you don't put a QWidget in between. Also, the hierarchy does end up being different. 

Consider this Qt Designer UI file:  http://pastebin.com/82W8Kne5
It is a QDialog, with a main horizontal layout, containing two vertical layouts, each with a push button. 
On the left side, the vertical layout is placed directly into the horizontal layout. 
On the right side, a placeholder widget is added first, then set with a vertical layout and then the push button.

Look at the hierarchy when I do this:

form = test.MyForm(win)
fullName = mui.MQtUtil.fullName
for name in ('layout1', 'button1', 'placeHolderWidget', 'layout2', 'button2'):
    obj = getattr(form, name)
    path = fullName(long(sip.unwrapinstance(obj)))
    print path

## output ##
MayaWindow|MayaTestDialog|layout1
MayaWindow|MayaTestDialog|mainLayout|button1
MayaWindow|MayaTestDialog|mainLayout|placeHolderWidget
MayaWindow|MayaTestDialog|mainLayout|layout2
MayaWindow|MayaTestDialog|mainLayout|layout2|button2

Notice that with the layout-within-layout, button1 isn't even showing that its a child of layout1
On the other side, button2 does show that its a child of layout2, yet layout2 still isnt showing that its a child of placeHolderWidget.
So, Maya does some under the hood reorganizing when it translates. When I try and setParent to layout1, for me Maya actually crashes completely. I'm not sure what OS you are running, and maybe because your UI is set up differently you just get a traceback. But, I can however setParent to layout2 just fine.

Ultimately, you have to be careful with how you expect to use a Qt layout in combination with the commands module UI widgets.

My final suggestion, regarding wanting to now add an attrFieldSliderGrp to your ui, is to stick with PyQt if you are already designing with it. You will reduce your limitations in trying to translate between the two worlds constantly. An attrFieldSliderGrp is basically a QLabel, a QLineEdit with a QDoubleValidator set on it, and a QSlider, all placed in a horizontal layout. And then you just cross connect the signals between the QLineEdit and QSlider. This may seem like more work rather than trying to just throw in an existing Maya widget, but what you get is more control over these items. You don't have to wonder what the translation will do, and you  have instant easy access to the complete range of signals, events, and even being able to wrap this up into its own nice subclass with customizations.

Hope this helps
-- justin


张宇

unread,
Mar 8, 2012, 10:22:46 PM3/8/12
to python_in...@googlegroups.com
Thanks a lot Super Cute Justin!
There is a small doubt, I know how to control the attribute with the QSlider, but how to change the silder's value by the attribute? Create a scriptJob? Then with the same problem, how to edit the QSlider's in maya.

2012/3/9 Justin Israel <justin...@gmail.com>



--
http://thatboy.me 


Justin Israel

unread,
Mar 9, 2012, 11:00:01 AM3/9/12
to python_in...@googlegroups.com
Thanks. As always…I am cute.

I'm not exactly sure what you want to be able to control from Maya. It would work just like any other python object, except you would use the methods of your pyqt widget, and not have to use the maya commands module.

In case what you meant is that you were having trouble linking the text field with the slider, I have thrown together a really fast and simple example of a pyqt attrFieldSliderGrp


It ties the field and slider together with signals, and uses a QDoubleValidator on the text field.

Any maya widget could have its command attribute set to a python command that modifies the pyqt widget. And yes you could also use a scriptJob if what you are doing is setting up the pyqt widget and then forgetting about it, and letting events fire that modify it. How you use the pyqt widget it totally up to you, but accessing its values is completely pythonic. You don't need the commands module for that.

I hope that helps a bit more. Sorry if I didn't fully understand your question. It might be the language barrier :-/
If you still have questions, maybe give an example so I can specifically see what your issue is.

-- justin
Reply all
Reply to author
Forward
0 new messages