How do I parent new, user-created buttons inside t

2019-04-16 18:05发布

问题:

I'd like to add some new buttons to the Maya Graph editor -- particularly on top of the Channel list with all the attributes in the left of the window. However I'd rather not muck around with the Maya Startup scripts for the Graph Editor itself. Is there a way to "parent" the new buttons I want inside every new Graph Editor window using a separate script?

Ideally this could be all Python.

回答1:

TL;DR;

if cmds.window("GE_ui_window", exists=True): #If the window exists
    cmds.deleteUI("GE_ui_window") #Delete it
cmds.window("GE_ui_window", title="My custom Graph Editor") #Create your custom win

cmds.frameLayout("GE_ui_frameLayout", p="GE_ui_window", lv=False, bv=False ) 

if cmds.scriptedPanel("GE_ui_scriptedPanel", exists=True): #If the scriptel panel already exists
    cmds.deleteUI("GE_ui_scriptedPanel") #Delete it
cmds.scriptedPanel("GE_ui_scriptedPanel", unParent=True, type="graphEditor")
cmds.scriptedPanel( "GE_ui_scriptedPanel", e=True, parent="GE_ui_window|GE_ui_frameLayout") #parent the scripted panel to your frame layout

cmds.showWindow("GE_ui_window")

channelLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[0] #Get the channel box's layout
filterLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[1] #Get the filter's layout

myRowLayout=cmds.rowLayout(numberOfColumns=3, p="GE_ui_scriptedPanelOutlineEdForm") #Create a row layout 
cmds.button(label="Café", h=100, p=myRowLayout) #Add some buttons
cmds.button(label="Clope", p=myRowLayout)
cmds.button(label="Caca", p=myRowLayout)

#This will reorder the content of the left formLayout
cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", edit=True, af=[ \
            (channelLayout, "bottom", 0), \
            (channelLayout, "right", 0),  \
            (filterLayout, "top", 0),  \
            (myRowLayout, "left", 0),  \
            (myRowLayout, "right", 0)],  \
            ac=[(myRowLayout, "top", 0, filterLayout), \
            (channelLayout, "top", 0, myRowLayout)])

There are two really usefull things to know when it comes to editing Maya's UI.

First thing is the History -> Echo all commands checkbox in your script editor. This can print out a lot of garbage with usefull pieces of information inside.

Second thing is the whatIs command (Doc).

This command takes one string type argument and returns a string indicating whether the argument is a builtin "Command", a "Mel procedure", a "Script", or a variable. If it is a variable, the type of the variable is also given. If the argument is a Mel procedure or a script file, the path to the file containing the script or procedure is included in the return value.

This combination will allow you to track down how and where the graph editor is created. Now let's do it.

1: Open the graph editor Window -> Animation Editors -> Graph Editor

GraphEditor;
tearOffPanel "Graph Editor" "graphEditor" true;
// Result: graphEditor1Window // 

GraphEditor; is a Run Time Command which executes tearOffPanel "Graph Editor" "graphEditor" true; when called. That's why it appears in the script editor.

2: Run whatIs "tearOffPanel"; (mel)

// Result: Mel procedure found in: C:/Program Files/Autodesk/Maya2014/scripts/startup/tearOffPanel.mel // 

With a little investigation in this file, you can deduce that you can create a whole new Graph Editor using the scriptedPanel command.

3: Create your own Graph Panel

The scriptedPanel doc show you how to create a scripted panel and include it in a window. You can now create you custom graph editor using this:

if cmds.window("GE_ui_window", exists=True):
    cmds.deleteUI("GE_ui_window")
cmds.window("GE_ui_window", title="My custom Graph Editor")

cmds.frameLayout("GE_ui_frameLayout", p="GE_ui_window", lv=False, bv=False )

if cmds.scriptedPanel("GE_ui_scriptedPanel", exists=True):
    cmds.deleteUI("GE_ui_scriptedPanel")
cmds.scriptedPanel("GE_ui_scriptedPanel", unParent=True, type="graphEditor", label='Sample')
cmds.scriptedPanel( "GE_ui_scriptedPanel", e=True, parent="GE_ui_window|GE_ui_frameLayout")

cmds.showWindow("GE_ui_window")

4: Try to understand how the Graph Editor is built

This script will print out the widget hierarchy of a Graph Editor (create your custom Graph Editor first):

nbIteration = 0
def getChildren(uiItem, nbIteration):
    for childItem in cmds.layout(uiItem, query=True, childArray=True):
        try:
            print "|___"*nbIteration + childItem
            getChildren(uiItem + "|" + childItem, nbIteration+1)
        except:
            pass
getChildren("GE_ui_window|GE_ui_frameLayout|GE_ui_scriptedPanel", nbIteration)

Also, you can check into C:\Program Files\Autodesk\Maya2014\scripts\others\graphEditorPanel.mel, @939: global proc addGraphEditor (string $whichPanel)

You can now realize that a lot of widgets are not given any name, only default name given by Maya. Hence, we can't add widgets and parent them using a full path because this path will change every time a new Graph Editor is created.

The item we will try to rely on is GE_ui_scriptedPanelOutlineEdForm which is a formLayout containing an other formLayout and a paneLayout.

|___|___GE_ui_scriptedPanelOutlineEdForm 
|___|___|___paneLayout123 #layout containing the two channel boxes
|___|___|___|___GE_ui_scriptedPanelOutlineEd
|___|___|___|___GE_ui_scriptedPanelOutlineEdSlave
|___|___|___formLayout276 #Layout containing the "filter part"
|___|___|___|___textField63 #It's text
|___|___|___|___iconTextButton102

5: Create your buttons and reorder the content of GE_ui_scriptedPanelOutlineEdForm

channelLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[0] #Get the channel box's layout
filterLayout = cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", query=True, ca=True)[1] #Get the filter's layout

myRowLayout=cmds.rowLayout(numberOfColumns=3, p="GE_ui_scriptedPanelOutlineEdForm") #Create a row layout 
cmds.button(label="Café", h=100, p=myRowLayout) #Add some buttons
cmds.button(label="Clope", p=myRowLayout)
cmds.button(label="Caca", p=myRowLayout)

#This will reorder the content of the left formLayout
cmds.formLayout("GE_ui_scriptedPanelOutlineEdForm", edit=True, af=[ \
            (channelLayout, "bottom", 0), \
            (channelLayout, "right", 0),  \
            (filterLayout, "top", 0),  \
            (myRowLayout, "left", 0),  \
            (myRowLayout, "right", 0)],  \
            ac=[(myRowLayout, "top", 0, filterLayout), \
            (channelLayout, "top", 0, myRowLayout)])


回答2:

To that, you may have to go with PySide/PyQt. Find the pointer of the graph editor and find how the elements are layouted.

Here is a sample about changing stylesheet of maya menu :

from maya.OpenMayaUI import MQtUtil as omui
import sip
from PyQt4 import QtGui

def changeMayaMenuColors(fontStyle='italic', fontWeight='bold', fontColor='cyan'):
    # Get the widget
    widgetStr = mel.eval( 'string $tempString = $gMainCreateMenu' )
    ptr = omui.findControl( widgetStr )
    widget = sip.wrapinstance(long(ptr), QtGui.QWidget)
    widget.setStyleSheet('font-style:%s;'%fontStyle +'font-weight:%s;'%fontWeight + 'color:%s;'%fontColor)

And here sonme experiments about channelBox :

from PySide import QtGui, QtCore
from shiboken import wrapInstance
from maya.OpenMayaUI import MQtUtil


channelbox = wrapInstance(long(MQtUtil.findControl('mainChannelBox')), QtGui.QWidget)
channelbox_children = channelbox.children()

first_widget = channelbox_children[0] # EDIT
first_widget.hide()
#first_widget.show()
#---------------------------------------------------------------------------------------------------------------
mySubWdget = first_widget.children()

new_button = QtGui.QPushButton()
new_layout = QtGui.QVBoxLayout()
first_widget.setLayout(new_layout)
new_layout.addWidget(new_button)

def print_hodor():
    print 'HODOR'

new_button.clicked.connect(print_hodor)

You can do this kingd of experiments with all maya widget (find the pointer and then use wrapInstance to get the QT pointer, then iterate throught children to find the layout you may want)

hope it helps