Reputation: 33
I've been working on a script for measuring the distance between 2 vertices that the user selects and scaling up or down that the object based on a desired length between those vertices.
Error states that it cannot locate the textFieldButtonGrp object that I create in one of my functions.
i basically put my window format stuff into a single function:
def window_presets():
'''
presets for UI window
'''
if mc.window("Distance Scale Tool", exists=True):
mc.deleteUI("Distance Scale Tool")
mc.window("Distance Scale Tool", t="Distance Based Scale Tool")
mc.rowColumnLayout(numberOfColumns=2,
columnAttach=(1, 'left', 0),
columnWidth=[(1,100), (2,300)])
mc.text(l="Current Length")
current_length = mc.textFieldButtonGrp("Current Length",
editable=False,
text="{0}".format(refresh_current_dist()),
buttonLabel="Refresh",
buttonCommand=refresh_current_dist)
mc.text(l="Desired Length")
desired_length = mc.textFieldButtonGrp("Desired Length",
buttonLabel="Scale",
buttonCommand=scale_dist,
tcc=refresh_scale_factor)
mc.showWindow()
i want the refresh button to call another function that edits the textFieldButtonGrp that i created:
def refresh_textfield(distance):
if mc.textFieldButtonGrp("Current Length", exists=True):
mc.textFieldButtonGrp("Current Length",
edit=True,
text="{0}".format(distance))
else:
print "Current Length dont exist"
but "Current Length".... it doesnt seem to exist....
same with "Desired Length"....
Heres the full script:
## ((Ax - Bx)**2 + (Ay - By)**2 + (Az - Bz)**2)**0.5
import maya.cmds as mc
import math
def window_presets():
'''
presets for UI window
'''
if mc.window("Distance Scale Tool", exists=True):
mc.deleteUI("Distance Scale Tool")
mc.window("Distance Scale Tool", t="Distance Based Scale Tool")
mc.rowColumnLayout(numberOfColumns=2,
columnAttach=(1, 'left', 0),
columnWidth=[(1,100), (2,300)])
mc.text(l="Current Length")
current_length = mc.textFieldButtonGrp("Current Length",
editable=False,
text="{0}".format(refresh_current_dist()),
buttonLabel="Refresh", buttonCommand=refresh_current_dist)
mc.text(l="Desired Length")
desired_length = mc.textFieldButtonGrp("Desired Length",
buttonLabel="Scale",
buttonCommand=scale_dist,
tcc=refresh_scale_factor)
mc.showWindow()
def get_object_name():
selPoints = mc.ls(sl=True)
obj_name = selPoints[0].split('.')[0]
return obj_name
def get_coordinates():
'''
Gets coordinates of selected points and gets distance between them
'''
selPoints = mc.ls(sl=True)
obj_name = get_object_name()
print obj_name
vtxCoordList = mc.xform(selPoints,
query=True,
translation=True,
ws=True)
Ax, Ay, Az = vtxCoordList[:-3]
Bx, By, Bz = vtxCoordList[3:]
return (Ax, Bx, Ay, By, Az, Bz)
def calculate_distance(Ax, Bx, Ay, By, Az, Bz):
'''
Determines distance between 2 coordinates on single mesh.
Below are formulas for distance based on single axis:
dx = ((Ax - Bx)**2)**0.5
print "Distance on X axis is: {0}".format(dx) #distance on X axis
dy = ((Ay - By)**2)**0.5
print "Distance on Y axis is: {0}".format(dy) #distance on Y axis
dz = ((Az - Bz)**2)**0.5
print "Distance on Z axis is: {0}".format(dz) #distance on Z axis
'''
distance = math.sqrt((Ax - Bx)**2 + (Ay - By)**2 + (Az - Bz)**2)
print "the distance between points is {0}".format(distance)
return distance
def refresh_textfield(distance):
if mc.textFieldButtonGrp("Current Length", exists=True):
mc.textFieldButtonGrp("Current Length",
edit=True,
text="{0}".format(distance))
else:
print "Current Length dont exist"
def refresh_current_dist():
'''
returns current distance
'''
current_coordinates = get_coordinates()
current_distance = calculate_distance(*current_coordinates)
refresh_textfield(current_distance)
return current_distance
def refresh_scale_factor(sf):
'''
returns factor by which object will be scaled
'''
current_distance = refresh_current_dist()
scale_factor = (float(sf))/(float(current_distance))
print "dist btwn pnts is d: {0}".format(current_distance)
print "sf is {0}".format(sf)
print "user input is {0}".format(sf)
print "scale factor is {0}".format(scale_factor)
print "-"*10
return scale_factor
def scale_dist():
'''
scale object to match measurement
'''
user_input = float(mc.textFieldButtonGrp("Desired Length",
query=True,
text=True))
scale_factor = refreshScaleFactor(user_input)
mc.makeIdentity(get_object_name(),
apply=True,
translate=1,
rotate=1,
scale=1,
normal=0,
preserveNormals=1)#freeze transformations
mc.DeleteAllHistory()
mc.scale(scale_factor, scale_factor, scale_factor, get_object_name())
print "you scaled by {0}".format(scale_factor)
mc.makeIdentity(get_object_name(),
apply = True,
translate=1,
rotate=1,
scale=1,
normal=0,
preserveNormals=1)#freeze transformations
if __name__ == '__main__':
window_presets()
Upvotes: 0
Views: 971
Reputation: 12218
@DrHaze is correct, your UI elements will not have spaces in their names: when you create
In general,. using a class is the easiest way to make sure that the UI elements you need are accessible to your functions: see here or here and extended discussion here
If you don't want to use a class you will need to make sure that the functions get the real name of your UI elements, not the name you are expecting.
Upvotes: 0
Reputation: 1318
Solution:
Remove the space in "Current Length"
and this will fix your error.
Naming notes:
Consider applying labels the same naming as the one you are using on functions. I usually name them this way:
"<mine or company initials>_<ToolName>_<WidgetName>"
In you case this will be something like "ak_VertexDistance_InputCurrentLength"
.
Why this naming?
Few months ago I was writing a script to save a Maya scene somewhere on the network. I was trying to add some items to an optionMenu
to my window, but whatever I was trying, the optionMenu
remained empty. After two hours of unsuccessful researches, I realised that the item were added to an other optionMenu
in an other of my tools. The widgets had the same generic name.
Your initials are optionnal but adding a <ToolName>
is in my opinion mandatory if you want to differenciate the widgets of your different tools.
Upvotes: 1
Reputation: 2573
This can be resolved two ways I think of:
The first is to create a CLASS surrounding all your functions and saving the textFieldButtonGrp in a class variable self.textField = textFieldButtonGrp(...)
.
This means creating a class encapsulating all of your functions, adding an __init__(self,*args)
function together with the rest, and probably adding self. everywhere it fails (function calls, calling variables...). And, as a plus, you will be able to save every item from the UI in a class variable, and use it in any funcion using self.variableName
The second aproach is to create the textField, keep it in a variable, and then pass it as an argument using that buttonCommand=partial(functionname,variable)
Where partial comes from:
from functools import partial
But the way to do this is first create the text field without the buttonCommand, and then execute the creation of the textField using edit mode (not create mode) Short explanation about execution modes
textFieldButtonGrp(variableName, edit=True, buttonCommand=partial(function,variableName)
)
So you edit the text field to add this buttonCommand afterwards.
I haven't tested this, but I'm sure any of them will work, specially the first. Hope this helps.
Upvotes: 0