Scripting examples for 2.5 - update: Mar 26th 2010

it looks like there is more thatn one way to add objects

1 - directly like

#cube
bpy.ops.object.mesh_add(type=‘CUBE’)

2 - from OT bpy…

MESH_OT_primitive_circle_add(32,rad,0)

what would be the difference between theses 2 ways.

an example i guess would be very nice to show the difference at this time
if possible

Thanks

Thanks for these little scripts. They are what i’m looking for.

Can I make my own toolbar using scripts?

Are there plans to add picked object support to Python scripting? It doesnt seem to be implemented and having it in place would really help. On a related note is there any way from within a Python script to enumerate all the instances of a particular object? Or a way to retrieve an object given its UID? At least with something like that I could try to work around the missing picked object support plus Im sure it would be useful for other things. Thanks in advance

to iterate through the objects


obs = bpy.data.objects
for o in obs:
    print(o)


the “hello world” example got the selected object with:


def draw(self, context)
    layout = self.layout
    ob = context.object


that didn’t seem to work when i tried it in the “toolbar” rather than buttons window though…(must try that again later)

getting by name did…

myOb = bpy.data.objects[‘Cube’]

This is going to be a long post, but there are a lot of things to address.

Ricky:

  1. I’m using a class, because the push button in the gui needs to refer to an operator. And the easiest way to create a new operator is to define a new class for it and then add it to blender’s list of known operators. You can of course add meshes outside of classes as well.
    2&5. The ‘select_all_toggle()’ line being there twice, is for a good reason. It works like pressing the A-key. So the first time you toggle it, it deselects all vertices and the second time it selects all vertices. To make sure that it always works like this, there needs to be at least one selected and one deselected vertex when you begin. That’s what the lines before ‘me.update()’ are for.
if context.active_object.type == 'MESH':

This does not do an action. Neither does it make a selection. You might want to read up a bit on python before you dive into Blender 2.5 (Byte of Python is a good read, and you can test your knowledge at Project Euler).
The active_object is a property of the context. I simply test if the type of that object is a mesh. It’s like bpy.data.scenes.active.objects.active in blender 2.4x
4.

layout.itemL(text="Change mesh:")
             layout.itemO("object.monkify")

This is what shows up in the gui. You can also see this in the screenshot.
6. I chose to do it in editmode, because then the new vertices are automatically inserted into the active object. Otherwise you have to start renaming or relinking objects and meshes, which is quite some more work.

Ricky (2nd post): Your example shows two different operators (the first is an object operator, the second is a mesh operator), but I think you’re being confused by the ways of referring to operators. It’s a good question though and a pretty important one. Take a look at this (examples for how you might code a pushbutton):

layout.itemO("object.object_add")
layout.itemO("OBJECT_OT_object_add")
layout.itemO(bpy.ops.object.object_add(type = "EMPTY"))

The first two are the same and create a pushbutton. They will invoke the operator when the buttons is pressed. The third one executes the operator and doesn’t create a button (itemO takes a string as argument). So you’ll end up with hundreds of empties after a few seconds as itemO is called on each redraw.
As you migh remember of the script examples so far that involved operators, we defined the ‘invoke’ part of the operator. If you wish to ‘execute’ an operator (so run it directly from your script) you need to define an ‘execute’ part as well (or replace the ‘invoke’ part with it, if you don’t want to use it with a gui).

demohero: what exactly do you mean with creating your own toolbar? A custom window, a bar in the 3d-view, a panel inside another window? Perhaps a quick mock-up image would help to explain what you mean.

Ammiddeon: In the monkify example I got the picked object using:

ob = context.active_object

For iterating objects, Michael W already gave the answer.

Michael W: The reason context.object doesn’t work in the toolbar, is because the context is different. In the ‘hello world’ example the context is ‘object’, while in the ‘monkify’ example the context is ‘objectmode’. And the ‘objectmode’ context doesn’t have an ‘object’ property. Both contexts do have the ‘active_object’ property though. So it’s probably best to use that.
You can try this yourself: if you replace “ob = context.object” in the ‘hello world’ example with “ob = context.active_object”, it will still work correctly.

1-events loopings on redraw

about this little phrase
" So you’ll end up with hundreds of empties after a few seconds as itemO is called on each redraw."

now your beginning to get into the problem
when you add a panel with buttons part of blender windows

there is the whole questions of looping events inside blender which as you indicated could create loop prolbem like getting 100’s of things on redraw

so how do you control that if you dont’ really define your own events and loops?
is there sort of a diagram showing what the loops are and where your interacting with it !

2 - operators
i did not really see the definition of operators
and difference between invoke and execute part for operators

now may be for an advanced programmer theses are concepts easy to understand
but for most people it’s not i guess

3 - you gave 3 ways to add

[LEFT]layout.itemO(“object.object_add”)
layout.itemO(“OBJECT_OT_object_add”)
layout.itemO(bpy.ops.object.object_add(type = “EMPTY”)

can you gie from which module theses command comes from[/LEFT]

object.object_add") module ?

bpy.ops.object.object_add(type = “EMPTY”) -guessing here this is BPYoperator

one thing in this new 2.5 is the fact that we sesm to be seing new technics of advance programmation included which might be good but really different from the old 2.49!

Thanks

Both of them would be good. I used Maya P.L.E before. Maya has a customizable toolbar. This toolbar includes every tool such as cut, split etc. In blender 2.5 I want to create a toolbar (using scripts) which includes useful tools such as knife, loopcut etc.

Is it possible. Will Blender 2.5 be as flexible as Maya’s toolbars? (with Pyton power)

Thanks, regards.

2.5 has a Tool window (press T in view3d).
You can add any tool (a registered operator) to its Toolshelf panel, even ones you defined and registered yourself. Saving into a file (as the tooltip promises) doesn’t seem to work (yet)

Answer time again :yes:.

Ricky:

  1. When things are drawn in a panel, they will be drawn on every redraw. So a button will be drawn several times a second, which is just what we want. However if you execute an operator inside a panel, it will also be executed every time. It is different for the operators which are defined in another place. They are invoked when the button is pressed, so they will only run one time (when the button is pressed).
    Of course when you don’t bother with a gui, your script will only be executed when you press alt+p in the text-editor. This is all pretty much the same as in blender 2.4x, with the difference that the gui isn’t drawn inside the text-editor but in a panel in another window.
    My next script example (next post) will show a script without a gui.

  2. Operators are simply classes that are of the operator type and are added to blender as such. Example (from the monkify script):


class OBJECT_OT_monkify(bpy.types.Operator):
    __idname__ = "OBJECT_OT_monkify"
     
    def invoke(self, context, event):
        # do something here
        return('FINISHED',)
bpy.ops.add(OBJECT_OT_monkify)

The last line adds the class to blender as an operator. The class itself is referred to by Blender by its idname. To make the class useful as an operator, there is an ‘invoke’ definition.
If a button asks blender to run the operator with the idname ‘OBJECT_OT_monkify’, blender will first look if there is a ‘poll’ definition. If there is and it returns False, blender will stop running the operator. If it returns True or if there is no ‘poll’ definition, it will look for the ‘invoke’ definition and run it.
If a script asks blender to run the operator, blender basically does the same thing. But now it won’t look for the ‘invoke’ definition, but for the ‘execute’ one.
By the way, this was the first time for me that I came across this concept. It’s basically a matter of studying the scripts that are already included with blender and then playing with it yourself.

  1. The documentation is still pretty confusing. Just use dir() a lot.
    There are two places in the docs where object.object_add can be found. In the bpy module and in the rna module. It basically comes down to the same thing.

demohero and varkenvarken: I think varkenvarken gave a good description of the current situation. As far as I can tell the toolshelf is still in development, but it looks like it’ll become exactly what demohero wants.

This post has been updated for Blender 2.5 build 26234

Script example 4

This is a script without a gui, which adds an armature to the scene.

from math import pi

bpy.ops.object.armature_add()
ob = bpy.context.scene.objects.active
arm = ob.data

bpy.ops.object.mode_set(mode='EDIT')
for i in range(3):
    bpy.ops.armature.extrude()
    bpy.ops.transform.translate(value=(0.0, 0.0, 1.0))

for i in range(len(arm.edit_bones)):
    eb = arm.edit_bones<i>
    eb.connected = True
    eb.roll = i*(20/180*pi)
    eb.tail[0] = eb.head[0] + 0.2*(i+1)
bpy.ops.object.mode_set(mode='OBJECT')

http://sites.google.com/site/bartiuscrouch/images/25_04.png

Simply copy-paste the script to the text-editor and run it once. The armature will show up at the position of the 3d-cursor.

[I]Analysis

I’m only going to highlight the new things.

armature_add() adds an armature to the scene (both the object and its armature data, which already contains 1 bone by default).
Then we get the new active object. To change the armature bones we don’t need the object, but its data (the actual armature). This is just the same as it was in blender 2.4x

The second block of code adds 3 extra bones to the armature. To do this we need to be in editmode. The way we add bones is very different from how it was done in 2.4x. In 2.5 we simply mimic the user actions to extrude a bone.
extrude() creates a new bone, but that command alone isn’t enough. Because the bone has a size of 0, blender will automatically remove it once we exit editmode. We can’t directly set the size of the bone either, since we don’t have a reference to it. We can only get that once we’ve exited editmode and the list of armature bones is updated. Unfortunately, when we do that, blender will have already removed the bone because its size is 0. The next line in the code is our way out of this catch 22.
transform.translate() This is the same command blender gets when you move the mouse and click to set the location of the new bone. You can test this for yourself by opening the console window inside blender (it’s a new window type), changing it from python to report and then grabbing an object and change its position to a new location. In the console you’ll see the ‘translate’ command printed.
When we create a new bone, it automatically becomes the selected bone. So when we extrude again, we’re extruding from the correct bone (the last child of the chain).

The third and last block of code changes the bones.
eb.connected is the most interesting of the properties we set. Because when we change the tail position of a previous bone, the bone after it won’t automatically change its head’s position. It simply assumes that it has an offset. We could fix this by setting the head property of the next bone to the tail property of the previous one, but the connected property is an alternative way.
eb.roll sets the roll. Take note that this value is in radians, while in blender’s ui it is displayed in degrees. If I’m not mistaken all angles are now in radians in the api. This is a huge improvement over the old api, which had both degrees and radians as well as degrees/10 (don’t ask).

it looks to me there are now in 2.5 2 sets of instructions

the 1- BPY operators
2- BPY data

1 -BPY operators
these class operators

seems to me that theses class and operators are use only if added inside blenders windows like when creating a new panel for instance.
but may be this would also give acces to all the internal values in the different panels inside each window (or old 2.49 buttons windows)
but also not running from inside a script as such !

invoke !
is it necessary that it be called invoke
cause this is only the first function inside the class?
or may necessary by definition to be recognised by blender internal

2 - BPY data
Theses commands are like the old 2.49 scripts running from inside a text script file
but cannot acces the variable inside the different window / panels in blender

3 - an example of using invoke and execute would be nice to see the diffferences
between theses 2 if you have this yet !

4- independant GUI
but then this could also mean that we wont have an indpendant GUI for scripting may be?

Thanks

one more to the list - Twitter in Blender:
http://blenderartists.org/forum/showthread.php?p=1457891#post1457891

Thanks for the sample scripts. They did helped me on that.
Cheers

Ricky: I’ll try and see if can think of a good example with both execute and invoke.

dfelinto: Nice script, I’ve added it to the table of contents. I’ll have a more in-depth look at it later and leave a comment in the twitter thread.

are we going to have an equivalent of select like we had in 2.49?

cause right now to iterate almost all the objects is not really practical!

I is there a list of icons
with symbols and name to select from
when adding one !

Thanks

Not one that is exposed in the Python API although it easy enough to get a list of the names from the source:https://svn.blender.org/svnroot/bf-blender/branches/blender2.5/blender/source/blender/editors/include/UI_icons.h

maybe they will be exposed in the future, there is a lot of development going on at the moment. Somewhere in the bpy.ui module would be a logical place so check it once in a while to see what is added there.

would be interesting to see a list of theses icons with the dwg beside and name

but is there a way on windnows to see theses icons like loading theses into paint program
i think can read theses icons

are theses equivalent to the icons for windows same size in bits?
like 24 X 24 or 48 x 48 ? and are theses blender incon identify the same way as for windows as ICO file if i remember well ?

or may be there a way to make a little script to see theses in blender ?

thanks

Did something changed since the last Blender versions? I tried the examples with a own build of today, and got “hello world”, the Armature-Add and Twitter to run. But no other. I cant see any errors in the console or the “DOS Window”.

BTW: Why are Python errors not showing up in the console-space?

Carsten

hello, thanks for this thread.
I allready did my first operator - conversion of grease pencil strokes to bevelled curves, with tablet pressure respecting. It works, but crashes blender often. anyway, here’s the code, for learning purposes, add it to the list if you want. Also, I still don’t know how to actually use the ‘options’ in there.

class VIEW3D_PT_tools_sketch_objectmode(bpy.types.Panel):
    __space_type__ = "VIEW_3D"
    __region_type__ = "TOOLS"
    __context__ = "objectmode"
    __label__ = "Sketch Tools "
    
    def poll(self, context):
        return context.active_object
    
    def draw(self, context):
        layout = self.layout
        
        layout.itemO("object.vsketch")
        #layout.itemR("object.vsketch.smooth",text='smooth')
        #layout.itemR("object.vsketch.hide_layer",text='hide layer')


class OBJECT_OT_vsketch(bpy.types.Operator):
    '''
    Operator documentatuon text, will be used for the operator tooltip and python docs.
    '''
    
    __idname__ = "OBJECT_OT_vsketch"
    __label__ = "Convert Sketch"
    __doc__ = "Convert Grease pencil to bevelled curves"
    
    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.
    
    __props__ = [ bpy.props.BoolProperty(attr="smooth", name="Smooth after stroke", description="Smooth curve verts after stroke conversion", default= True),bpy.props.IntProperty(attr="hide_layer",
            name="objects hide layer", description="To which layer should be hidden invisible frames during animation", default= 524288)
    ]
    

    def poll(self, context):
        print("Poll")
        return context.active_object
    
    
    def apply(self,context):
        ob=context.active_object
        bpy.ops.view3d.snap_cursor_to_active()
        gplayers=ob.grease_pencil.layers
        print(dir(ob.grease_pencil))
        for l in gplayers:
            for f in l.frames:
                i=0
                
                for s in f.strokes:
                    print (f.frame_number)
                    
                    bpy.ops.object.curve_add()
    
                    bpy.ops.object.editmode_toggle()
                    c=context.active_object
                    c.data.dimensions='3D'
                    c.curve_2d=0
                    c.data.front=0
                    c.data.back=0
                    c.name=ob.name+'_sketch_'+str(f.frame_number)
                    bpy.ops.curve.de_select_first()
                    for p in s.points:
                        co=p.coordinates
                        bpy.ops.curve.vertex_add(location=(co[0],co[1],co[2]))
                        bpy.ops.curve.radius_set(radius=p.pressure*l.line_thickness/10.0)
                    bpy.ops.curve.select_all_toggle()
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.select_all_toggle()
                    bpy.ops.curve.handle_type_set(type='AUTOMATIC')
                    #bpy.ops.curve.smooth()
                    #bpy.ops.curve.smooth()
                    #bpy.ops.curve.smooth()
                    bpy.ops.curve.select_all_toggle()
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.select_every_nth(n=2)
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.select_every_nth(n=2)
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.select_every_nth(n=2)
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.de_select_first()
                    bpy.ops.curve.select_every_nth(n=2)
                    bpy.ops.curve.delete(type='SELECTED')
                    bpy.ops.curve.select_all_toggle()
                    print (c.data.draw_handles)    
                    c.data.draw_handles=0
                    c.data.draw_normals=0
    
                    for s in c.data.splines:
                            print (s.resolution_u)
                            s.resolution_u=1
                            s.cyclic_u=1
                            s.resolution_v=1
                    c.data.resolution_u=1
                    c.data.resolution_v=1
                    c.data.bevel_depth=0.03
                    c.data.bevel_resolution=2
                    bpy.ops.object.editmode_toggle()
                
    def execute(self, context):
        print( 'hello world')
        #print(Crv)
        
        return ('FINISHED',)
    
    def invoke(self, context, event):    
        self.apply(context)
        return ('RUNNING_MODAL',)

bpy.ops.add(OBJECT_OT_vsketch)
bpy.types.register(VIEW3D_PT_tools_sketch_objectmode)

Nice script pildanovak. Thanks for your share.

I’m currently extremely short of time (got to run for my train), but I’ll have a good look at everything after the weekend.
Just so peole know that I haven’t abandoned this thread.