calling mel.eval inside button command


#1

Hello Guys,

I am trying to code something in python inside maya. I am calling this mel function inside the button command. When I click on the button, it gives syntax error. Cant find where is the problem.

Anybody can help?

import maya.cmds as cmds
import maya.mel as mel

winID = ‘Paint Weights Tool’
if cmds.window(winID, exists=True):
cmds.deleteUI(winID)

cmds.window(winID)

cmds.columnLayout()

cmds.button(label=‘paint’, command=‘mel.eval("artSetToolAndSelectAttr( “artAttrCtx”, “blendShape.blendShape1.baseWeights” ")’)

cmds.showWindow()

thanks,
Rohit


#2

Your button command has mismatched parentheses and misplaced/unnecessary quotes. It should look like:

cmds.button(label=‘paint’, command=‘mel.eval(“artSetToolAndSelectAttr artAttrCtx blendShape.blendShape1.baseWeights”)’)

That will work but using a string can cause problems, it’s better to use the partial function:

import maya.cmds as cmds
import maya.mel as mel
from functools import partial

def doMelCmd(*args):
    mel.eval(args[0])
    
winID = 'Paint_Weights_Tool'
if cmds.window(winID, exists=True):
    cmds.deleteUI(winID)

cmds.window(winID)
cmds.columnLayout()
cmds.button(label='paint', command=partial(doMelCmd, 'artSetToolAndSelectAttr artAttrCtx  blendShape.blendShape1.baseWeights'))

cmds.showWindow()

#3

Thanks Spire2,

It worked :slight_smile:

I just copied the same syntaxes what “Echo all commands” gave me when I manually activated the blendShape paint weights tool. I thought we were supposed to copy-paste the mel output as it is inside mel.eval command. But thats not the case I think.

I will try to read more about it.

Many Thanks !!
Rohit


#4

Hi Spire2,

Is there any way to call the python variable inside mel eval ? I want to do something like this:

def doMelCmd(*args):
mel.eval(args[0])

winID = ‘Paint_Weights_Tool’
if cmds.window(winID, exists=True):
cmds.deleteUI(winID)

cmds.window(winID)
cmds.columnLayout()
cmds.button(label=‘paint’, command=partial(doMelCmd, ‘artSetToolAndSelectAttr artAttrCtx [CALL PYTHON VARIABLE HERE]’))

cmds.showWindow()


#5

I don’t think I understand your question; you want to say something like this?

myVar = ‘someValue’
cmds.button(label=‘paint’, command=partial(doMelCmd, 'artSetToolAndSelectAttr artAttrCtx ’ + myVar))

Yes of course that will work (assuming myVar was actually something valid), or did you mean something different?


#6

yeah, thats exactly I want, I tried that but its giving me an error:

"Wrong number of arguments on call to artSetToolAndSelectAttr. # "

Not sure if something else is wrong with my code, here is the code:

import maya.cmds as cmds
import maya.mel as mel

winID = ‘Paint Weights Tool’

if cmds.window(winID, exists=True):
cmds.deleteUI(winID)

cmds.window(winID)

cmds.columnLayout()

#cmds.artAttrSkinPaintCtx(‘artAttrSkinPaintCtx3’)
#cmds.setToolTo(‘artAttrSkinPaintCtx3’)
paints = cmds.artBuildPaintMenu();

paintsAttrsRemoveExtraChar = paints.replace(".1", “”)

paintAttrs = paintsAttrsRemoveExtraChar.split()

def doMelCmd(*args):
mel.eval(args[0])

for index in range(len(paintAttrs)):
cmds.button(label=paintAttrs[index], command=partial(doMelCmd, ‘artSetToolAndSelectAttr artAttrCtx’ + paintAttrs[index]))

Display the window

cmds.showWindow()

Basically I am trying to build a script where I dont have to right click to access the paint options, I can just click a button in my shelf and it gives me a pop up including all my paintable weights.


#7

In the code you posted, the variable “allAttrs” is never defined, did you miss that line in copy/paste? I would have thought you’d get an error about that first otherwise. But aside from that, the actual message you did receive is because you forgot to include a space at the end of your string literal (concatenating your variable directly to ‘artAttrCtx’):

command=partial(doMelCmd, 'artSetToolAndSelectAttr artAttrCtx' + paintAttrs[index]))

should be (notice the space before the closing quote):

command=partial(doMelCmd, 'artSetToolAndSelectAttr artAttrCtx ' + paintAttrs[index]))

P.S. When you paste code from your editor to the forum, please put it between code tags so it will format properly. That way it’s easy for someone else to test.


#8

Hi Spire2,

I appriciate your quick response, thank you :slight_smile:

Yeah, I had pasted an old code where I was using “allAttrs” variable, but I edited my post immediately and replaced “allAttrs” with “paintAttrs”. I think you did not get my edited post.

Wow, I am learning discovering new things about coding :). I just tested the code again with the space before closing quote and it works. But I did not understand why we need a space there. Would you mind explaining it little bit? Or if you could point me to a link where these rules are explained, I can have a look :slight_smile:

Thanks again,
Rohit


#9

rsj123 the missing space is just a simple syntax error really :slight_smile: Say you typed this mel command:

artSetToolAndSelectAttr artAttrCtx blendShape.blendShape1.baseWeights;

Okay that works fine. Now, take out the space after artAttrCtx. You would have this instead:

artSetToolAndSelectAttr artAttrCtxblendShape.blendShape1.baseWeights;

By forgetting the space, you’ve turned two strings into one. So you are calling the command with only a single argument when it expects two. That’s what was happening in your newer version.

I hope this helps you see it clearly, I think the extra clutter of calling a mel command from python through a button has made it seem more complicated to you than it is. But really it was just a typo.

This online textbook has some practical info about button commands under the heading “Executing Commands with GUI Objects” on page 193 (as the pdf viewer measures it) or page 201 (as printed on the actual pdf page):

https://profs.info.uaic.ro/~avitcu/FII%202015-2016/Animatie%203D_Documentatie/NEW!%20PthM.pdf


#10

Hi Spire2,

Sorry for late reply.

Yeah, that clears up my confusion. :slight_smile:

thank you so much again for your help, I will write here again in case of any more questions :slight_smile:

Best,
Rohit


#11

Hi Spire2,

I am stucked in another problem related to a new script I am working on.

I am trying to paint the blendshape weights on the selected vertices using python:

If I do this way, it looses the exact vertex IDs and sets the blendshape weights on the very first 8 vertices, but thats not what I want. I want to set the blenshape weights on my selected vertices.



import maya.cmds as mc

cmds.polySphere()
cmds.polySphere()

mc.blendShape('pSphere2', 'pSphere1')
mc.setAttr("blendShape1.pSphere2", 1)

mc.cluster('pSphere2')

cmds.xform( r=True, t=(-3, 0, 0) )

selectedVerts = [u'pSphere1.vtx[160]', u'pSphere1.vtx[178]', u'pSphere1.vtx[179]', u'pSphere1.vtx[180]', u'pSphere1.vtx[198]', u'pSphere1.vtx[199]', u'pSphere1.vtx[200]', u'pSphere1.vtx[218]', u'pSphere1.vtx[219]'] #

#mc.select(selectedVerts)

for i in range(len(selectedVerts)):
    mc.setAttr('blendShape1.inputTarget[0].baseWeights[%s]'%i, 0)


 

And if I remove the range and len from the for loop and do it this way:



for i in selectedVerts:
    mc.setAttr('blendShape1.inputTarget[0].baseWeights[%s]'%i, 0)

 

it gives me following error:

Error: RuntimeError: file <maya console> line 2: setAttr: Invalid attribute name: blendShape1.inputTarget[0].baseWeights[pSphere1.vtx[160]]

which make sense, because “baseWeights[]” attribute is supposed to take only the int.

Any ideas how do we solve this?

Thanks,
Rohit


#12

The way you’re doing it, it looks like you just need to pull the indices out of the strings. Something like:

for vert in selectedVerts:
    index = vert.rpartition('[')[2][0:-1]
    mc.setAttr('blendShape1.inputTarget[0].baseWeights[%s]'%index, 0)

#13

Oh Man!

Thats exactly I wanted, to keep indices out of the strings. I have been trying to do that for past two days and searched all over internet but couldn’t find anything.

I really appreciate your help again ! :slight_smile:

best,
Rohit