2
$\begingroup$

Part of my project involves integrating functionality similar to a graphing calculator into the image editor of Blender. Once complete this will just be a nifty little time saver that helps avoid leaving Blender to bring up other tools.

I'm using bpy.props.FloatProperty for a few metrics, such as domain minimum and maximum, so that they can quickly be set in Blender for an algebraic function to be drawn.

I don't want to work with these directly from the bpy.props objects because to do so would sacrifice usability. For example, we're used to a straightforward scale metric in Blender where if we want an object scaled to 50% on the x-axis, we simply set the x-axis scale to 0.5. But in an algebraic function where the vertical depends upon the horizontal, this fifty percent scaling is actually accomplished by multiplying the independent variable by two.

So, it helps the user to have something sit between the interface and all the math going on under the hood. That is exactly the kind of thing the update, set, and get fields are meant for in bpy.props objects.

The problem is that I can't find an example about how to format that string.

set = "self.set_thing ( )" ?
set = "self.set_thing" ?
self = "set_thing" ?
set = "self.set_thing ( self, thing )" ?
set = "set_thing ( self, thing )" ?  

There are probably possibilities there that I'm not thinking of yet. But how exactly do we format that and what are the restrictions? Do the set methods have to be in the object class that the bpy.props object is a data member of? Can it be any object, i.e. set = "thing_container.set_thing(thing)"?

Finally, with a getter and a setter field, what functionality does the update field have? Does this just allow for another method call in addition to the setter, whenever the setter is called?

$\endgroup$
3
$\begingroup$

Got it!

This page addresses how to get a function name, in a way that's friendly to class methods and not just script-scope functions. Blender API requires a 'self' parameter in the specified function for update, set, and get, so it actually requires a class method anyway.

So, let Python do the formatting for you.

update: I had a partial answer here before. I want to force use of the local dictionary, so that I know for sure that an instantiated object's method is used and that no global method is looked for. The answers for this question provide the second part. Also, the incomplete answer I had before does not work because it uses a string where a function is expected.

Here's an example using the lower domain constraint in my script:

global set_domain_min

self["domain_left"] = bpy.props.FloatProperty( 
    name="x >=", 
    description="Domain left bound", 
    default=-10, 
    min=-sys.maxint - 1, 
    max=sys.maxint,
    step=1,
    precision=6,
    subtype="DISTANCE",
    unit="LENGTH",
    set=locals()[self.set_domain_min.__name__]     
)

I don't know if this is a duplicate topic, since it's specific to Blender's API requirements but is answered with a general Python question. My last question was marked as a duplicate, and is, but I haven't deleted it because I think the original has poor wording for the topic. Next time I happen by this site, if a mod has marked this as a duplicate then I'll just delete it. The answering topic isn't obvious for somebody learning Python using the Blender API, but I'll leave this to others' judgment.

Update: Alternatively, the following can be used...

class foo:  
    def __init__(self):
        self["bar_prop"] = bpy.props.FloatProperty(set=self.set_bar)
        self["bar"] = 1 / self["bar_prop"]

    def set_bar(self, bar_in):
        self.bar = 1 / bar_in

This makes it unnecessary to use locals ( ), but the 'self' identifier is needed. Using locals ( ) is only necessary if there's an identifier with the same name declared global in-scope. The first code snippet I posted above has been updated to demonstrate. This can be useful for overloading an identifier such that the local is only used in specific cases.

$\endgroup$
  • $\begingroup$ Instead of set = locals () [self.set_domain_min.__name__] can't you do set = self.set_domain_min? $\endgroup$ – WorldSEnder Sep 18 '14 at 14:58
  • $\begingroup$ I'm not sure. I can't really test it for this case until I finish a bunch of calculus in other classes, remind myself of how to register classes, and learn how to modify the user interface. The documentation shows it done that way, but it's in the global scope, so I'm using overkill to play it safe. I'm not sure why functions in the global scope in the documentation have a 'self' parameter. What is 'self'? The file? Hopefully this will get a proper test here soon. This is one of those rare cases when a ton of functionality has to be complete before anything can be tested at all. $\endgroup$ – user2813810 Sep 19 '14 at 1:21
  • $\begingroup$ the self in the set() and update()-methods is the object the attribute is applied to. For example suppose bpy.types.Object.attr = StringProperty(update=example). self in this case would be the instance of bpy.types.Object attr is set. $\endgroup$ – WorldSEnder Sep 19 '14 at 1:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.