I'm trying to update some attribute values in Maya via code and I'm having a really tough time accessing them.
I need the attributes displayed name, (I'm pretty sure this is supposed to be their 'Nice Name'), but I can't seem to get them in any way. Using listAttr or using OpenMaya's MFnAttribute both don't give me what I want - they pass back long names and short names and cleaned up 'Nice Names' but none of those are the displayed UI name to the attributes.
As an example my node contains an attribute with the name 'Horizontal Damping Factor' under a drop down titled 'Advanced Anchor Controls.' When I query the node for a list of attribute nice names I get the similar name 'Anchor HDamping Factor', but that is not the displayed name. This is true for 23 other attributes as well.
Do you have any ideas on what's going on?
(All of these attributes are located in fields two dropdowns deep as well, is that a problem?)
EDIT: It's definitely because the attributes are two dropdowns deep... I still have no idea what these dropdowns are called or how to access the attributes contained inside of them.
EDIT 2: Well, I was wrong, the name of the attribute IS different from the name that's displayed, (when I adjust a slider the editor window shows the name of the value I just changed, which is different from the displayed name, and it's not just a 'Nice' name version of it either.) Still trying to figure this out.
EDIT 3: Not sure how clear this is but it shows the discrepancy between the UI label of the attribute and the 'Nice Name.' There is no 'Horizontal Damping Factor' in the list of attribute names.
FINAL EDIT: Looks like it's not possible to change the value of an attribute by querying the UI name if the attribute was given a different UI name then the authoritative name on creation. Created my own mappings in code instead.
The authoritative names are the ones in listAttr; the names you see in the UI are not reliable because an AETemplate can override them in any way it wishes. The AE often presents fake attributes which are used to calculate the real values -- for example, cameras have an angleOfView in the attribute editor, but setting it actually changes the focalLength attribute; there is no angleOfView on the camera node.
So, you may need to do some detective work to figure out what the visible UI is really doing. Playing with the sliders and watching the history is the usual first step.
FWIW
dict(zip(cmds.listAttr(), cmds.listAttr(sn=True)))
will give you a dictionary mapping the long names to the short names, which can be handy for making things more readable.
If you knew the longName of the attribute in question and the name of the node it is part of, you can use attributeQuery with the longName, shortName or niceName to get the it's long name, short name and nice name respectively.
From what I understand from your question, you want to be able to look at ll of this information for all the attributes of the node so you can make the right decision of which attribute to choose to do what you are doing. Here is a quick script I wrote, a simple query of sorts, to give you just that: (Interspersed generously with explanation as comments)
import maya.cmds as cmds
def printAttributes(node, like=''):
''' Convinience function to print all the attributes of the given node.
:param: node - Name of the Maya object.
:param: like - Optional parameter to print only the attributes that have this
string in their nice names.
'''
heading = 'Node: %s' % node
# Let's print out the fancy heading
print
print '*' * (len(heading)+6)
print '** %s **' % heading
print '*' * (len(heading)+6)
# Let's get all the attributes of the node
attributes = cmds.listAttr(node)
# Let's loop over the attributes now and get their name info
for attribute in attributes:
# Some attributes will have children. (like publishedNodeInfo)
# We make sure we split out their parent and only use the child's name
# because attributeQuery cannot handle attributes with the parentName.childName format.
attribute = attribute.split('.')[-1]
# Let's now get the long name, short name
# and nice name (UI name) of the atribute.
longName = cmds.attributeQuery(attribute, node=node, longName=True)
shortName = cmds.attributeQuery(attribute, node=node, shortName=True)
niceName = cmds.attributeQuery(attribute, node=node, niceName=True)
# if we the 'like' parameter has been set, we'll check if
# the nice name has that string in it;
# else we skip this attribute.
if like and like.lower() not in niceName.lower():
continue
# Now that we have all the info we need, let's print them out nicely
heading = '\nAttribute: %s' % attribute
print heading
print '-' * len(heading)
print 'Long name: %s\nShort name: %s\nNice name: %s\n' % (longName,
shortName,
niceName)
if __name__ == '__main__':
# Let us get a list of selected node(s)
mySelectedNodes = cmds.ls(sl=True)
# Let us do the printAttributes() for every selected node(s)
for node in mySelectedNodes:
# Just for example, just printing out attributes that
# contain the word 'damping' in their nice (UI) name.
printAttributes(node, like='damping')
Note that we use the command listAttr() to get a list of all the attributes of the node. Note that we can also use attributeInfo() to get a list of the attributes also. The advantage of attributeInfo() over listAttr() is that attributeInfo() has more filter flags to filter out the list based on various parameters and properties of the attributes.
It is worth it to go check out the documentation for these:
attributeQuery
attributeInfo
listAttr
Related
Sorry for noobster question again.
But I'm trying to do some very easy stuff here, and I don't know how. Documentation gives me hints which do not work, or apply.
I recieve a POST request and grab a variable out of it. It says "name".
I have to search all over my entities Object (for example) and find out if there's one that has the same name. Is there's none, I must create a new Entity with this name. Easy it may look, but I keep Failing.
Would really appreciate any help.
My code currently is this one:
objects_qry = Object.query(Object.name == data["name"])
if (not objects_qry ):
obj = Object()
obj .name = data["name"]
obj .put()
class Object(ndb.Model):
name = ndb.StringProperty()
Using a query to perform this operation is really inefficient.
In addition your code is possibly unreliable, if name doesn't exist and you have two requests at the same time for name you could end up with two records. And you can't tell because your query only returns the first entity with the name property equal to some value.
Because you expect only one entity for name a query is expensive and inefficient.
So you have two choices you can use get_or_insert or just do a get, and if you have now value create a new entity.
Any way here is a couple of code samples using the name as part of the key.
name = data['name']
entity = Object.get_or_insert(name)
or
entity = Object.get_by_id(name)
if not entity:
entity = Object(id=name)
entity.put()
Calling .query just creates a query object, it doesn't execute it, so trying to evaluate is as a boolean is wrong. Query object have methods, fetch and get that, respectively, return a list of matching entities, or just one entity.
So your code could be re-written:
objects_qry = Object.query(Object.name == data["name"])
existing_object = objects_qry.get()
if not existing_object:
obj = Object()
obj.name = data["name"]
obj.put()
That said, Tim's point in the comments about using the ID instead of a property makes sense if you really care about names being unique - the code above wouldn't stop two simultaneous requests from creating entities with the same name.
My problem is as follows:
I am implementing a labeling system for a machine learning problem.
So in short: A complex object should get a simple label information (like a tag).
There should be just one label per object and the set of labels is limited and static.
(e.g.: I want to label all attributs of one animal objects to the information CAT, DOG, etc.)
So I have an item object. I want to save this as a tupel with one of my label-objects (myAnimal, label). This object should only carry ONE information (e.g. DOG). How can I accomplish that?
I thought of an object that holds some booleans and the one boolean I want gets set, but that seems to be not a nice solution since multiple booleans could be set.
I googled for a simple enum-like solution but found nothing satisfying.
It would be nice if you could help me out here ;)
Since your labels are static and pre-defined:
TAGS = ((1,'DOG'),(2,'CAT'),(3,'HORSE')) # and so on
class MyThing(models.Model):
name = models.CharField(max_length=200)
tag = models.IntegerField(choices=TAGS)
With this model, your thing can only have one tag, and you can get the associated tag for your object thus:
foo = MyThing.objects.order_by('?')[0] # get some random object
print 'My object is a ',foo.get_tag_display()
What about a simple model with some relations ?
class LabeledItem(models.Model):
my_object= models.OneToOneField(Item)
label = models.CharField()
The label property could also be a OneToOneField to for example a Label model which has a name as field property.
I'm writing an exporter for a game my friend and I are making and it involves setting custom properties and tags to objects which are then recognized in the game and dealt with accordingly. Our engine, which is written in C/C++ has been successfully tested with my current version of the export script, and I''m currently working on tidying it up.
The script uses Blender's feature of custom properties to write custom tags to output file. The model typically consists of multiple 'parts' (Blender mesh objects that are parented to form a tree, with one 'parent' and multiple 'child' objects) and some of those parts are simple Blender Empty objects (for only it's X, Y and Z coordinates are needed) with custom properties that mark where things like ship's propulsion (it's a 3D shooter) are placed, or where the flames/explosions appear when ship's been shot. Those empty parts are also parented to either 'root' object or any of it's children. So far it's been working good, I have written a generic Operator class and some extended classes that reside in a panel which set part's properties (pretty handy since you don't have to add those custom properties by hand).
Now I want to speed thing up even more, that is to be able to simply click on an operator of desired type, and it should automatically add it to the scene and parent it to the active/selected object. I know how to do that, but I can't get those operators to change their labels. Basically, what I want is to operator to say 'Bullet point' when an existing empty is selected (I've got that part done), and when there's a mesh object selected to say 'Add bullet point'. So I just need a way to dynamically change operators' labels depending on the context (as the title of the question states clearly :))
This is what I got so far:
class OBJECT_OT_tg_generic (bpy.types.Operator):
bl_label = "Sets Generic Part Type"
bl_idname = "rbm.set_generic_part_type"
OB_TYPE = None
#classmethod
def poll (cls, context):
act = context.active_object
if 'Type' in act.keys ():
if act['Type'] == cls.OB_TYPE:
cls.bl_label = 'foo'
print (cls.bl_label)
# this prints foo but doesn't change the label
return False
return True
def execute (self, context):
# TODO: add code to automatically place empties and parent them to active object
bpy.context.active_object['Type'] = self.OB_TYPE
return{"FINISHED"}
And an example of a subclass:
class OBJECT_OT_tg_bullet_point (OBJECT_OT_tg_generic):
bl_label = "Bullet Point"
bl_idname = "rbm.set_bullet_point"
OB_TYPE = OT_BULLET_POINT
Here's how it looks in Blender:
http://i.imgur.com/46RAS.png
Guess I solved it. When you're adding an operator to a panel, you can do something like this:
def draw (self, context):
layout = self.layout
row = layout.row()
row.operator("foo.bar", text="Whatever you want")
and the "Whatever you want" is going to be your button's label. But what I did was something else. I didn't change the operators' labels, but instead gave them a different icons depending on whether it's a mesh or an empty currently selected/active:
def draw (self, context):
# (...) we're skipping some code here, obviously
act = context.active_object
if act.type == 'MESH':
op_icon = 'ZOOMIN'
else:
op_icon = 'EMPTY_DATA'
row = layout.column(align=True)
row.operator('rbm.set_bullet_point', icon=op_icon)
row.operator('rbm.set_rocket_point', icon=op_icon)
# (...) rest of the code
I have a blender scene with a few objects, I would get the object name when mouse is over one of them, setting a property of an empy object.
What I have now is just the list of the scene objects. What can I do?
import GameLogic
cont=GameLogic.getCurrentController()
obj=cont.getOwner()
print obj
objlist=GameLogic.getCurrentScene().getObjectList()
print objlist
sen=cont.getSensor('sensor')
if sen.isPositive():
print objlist[0]
PropName=.... #how to set this with the object name?
print PropName
I suppose you can use SCA_MouseSensor sensor and its hitObject property to get the last object the mouse was over. It returns None or an object of KX_GameObject type. When you get it, you can use its name property to get the name (or just access other properties of the object).
Reference links:
SCA_MouseSensor in API documentation
KX_GameObject in API documentation
I haven't tested this yet, but I suppose it should work when used in Blender Game Engine. The information I've found refers to Blender 2.59, so make sure use are using appropriate version of the application.
In order to be useful to someone else, I answer my own question. What I've done was to set a mouse over sensor to each objects within the scene and that add a python script controller, in order to set a property of the scene Empty object.
import GameLogic
import Rasterizer as r
r.showMouse(1) #just in order to get the mouse visible within the game engine
print 'SetProperty.py\n'
cont=GameLogic.getCurrentController()
obj=cont.getOwner()
emptyOb = GameLogic.getCurrentScene().getObjectList()["OBEmpty"]
emptyOb.EmptyProp=obj
print 'object name, within emptyProp: ', emptyOb.EmptyProp
My question is if we can assign/bind some value to a certain item and hide that value(or if we can do the same thing in another way).
Example: Lets say the columns on ListCtrl are "Name" and "Description":
self.lc = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
self.lc.InsertColumn(0, 'Name')
self.lc.InsertColumn(1, 'Description')
And when I add a item I want them to show the Name parameter and the description:
num_items = self.lc.GetItemCount()
self.lc.InsertStringItem(num_items, "Randomname")
self.lc.SetStringItem(num_items, 1, "Some description here")
Now what I want to do is basically assign something to that item that is not shown so I can access later on the app.
So I would like to add something that is not shown on the app but is on the item value like:
hiddendescription = "Somerandomthing"
Still didn't undestand? Well lets say I add a button to add a item with some other TextCtrls to set the parameters and the TextCtrls parameters are:
"Name"
"Description"
"Hiddendescription"
So then the user fills this textctrls out and clicks the button to create the item, and I basically want only to show the Name and Description and hide the "HiddenDescription" but to do it so I can use it later.
Sorry for explaining more than 1 time on this post but I want to make sure you understand what I pretend to do.
Instead of using the ListCtrl as your data structure, you could keep a separate list/dict of objects that contain all the information you want and refresh the ListCtrl from your other data structure.
For example:
class MyObject(object):
def __init__(self, name, description, hidden_description):
self.name = name
self.description = description
self.hidden_description = hidden_description
Then in your application:
def __init__(self):
self.my_items = {}
self.lc = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
self.lc.InsertColumn(0, 'Name')
self.lc.InsertColumn(1, 'Description')
def addItemToMyListCtrl(self, name, description, hidden):
new_item = MyObject(name, description, hidden)
self.my_items[name] = new_item
self.lc.Append((new_item.name, new_item.description))
Then when you want to use your additional data you can just look up the correct item in the dictionary and your data will be there.
the wxListCtrl lets you associate arbitrary data with an item, that will not be displayed - read the docs for the following methods:
SetItemData
GetItemData
FindItemData
The wxListItem class also has GetData and SetData methods.
You could always set the width of the hidden column to zero, that might accomplish what you want. I just tried it in a C++ (non-wx) program and it worked fine.
wx.ListCtrl doesn't let you associate a python object with an item like wx.TreeCtrl does with its extremely useful SetPyData() method (and corresponding GetPyData()).
I haven't tried it myself, but there is code here that shows how to create a class to mix in python data with a list. Although I'll admit, it's not clear to me how you're meant to use it.
It also might be possible to directly inherit from wx.ListCtrl, and add the appropriate methods, but I haven't seen any attempts at that anywhere, so it may be harder than I'm thinking.
Alternately you can just use SetItemData() to store an int in each item, and use that int to index a dict (or list, if the items are ordered reliably and consistently) that contains the associated objects. tgray has already shown how to do this, and it's listed at the page I link above as well, so I won't go over it again.