Calling a function from a button

Hello, I am new to Python in Blender ( and python in general). I’m sure this will be very basic. I am trying to make a panel with a button which calls a function. I am having a hard time finding examples of that. I have seen examples of buttons use to spawn things or call existing blender functions but none showing the use of custom functions.

Hope someone can help.
Thanks

Have you checked the Templates in the Text Editor?

And read here: http://wiki.blender.org/index.php/Dev:2.5/Py/Scripts/Cookbook/Code_snippets/Interface

This prepends a custom operator to the 3D View header:

import bpy



class SimpleOperator(bpy.types.Operator):
    """Tooltip"""
    bl_idname = "object.simple_operator"
    bl_label = "Simple Object Operator"

    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        self.report({'INFO'}, "Button clicked!")
        return {'FINISHED'}


def draw_func(self, context):
    layout = self.layout
    layout.operator("object.simple_operator")
    

def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.types.VIEW3D_HT_header.prepend(draw_func)


def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.types.VIEW3D_HT_header.remove(draw_func)


if __name__ == "__main__":
    register()


Run script, hover with mouse over 3D View header, then click the button!

Hey, thanks for the example. I tried modifying it to call a custom class however I cant get it to work. I modified the message in execute and it compiles fine but only seems to display the default message when the button is clicked. Also the caption on the button is the default one. I know I must be doing something wrong…

Here is my code:


bl_info = {
    "name": "Exploded Bake",
    "category": "Render",
}


import bpy


class ExplodedBake(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Exploded Bake"
    bl_idname = "OBJECT_PT_exploded"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


    class SimpleOperator(bpy.types.Operator):
        """Tooltip"""
        bl_idname = "object.simple_operator"
        bl_label = "Button text"

        @classmethod
        def execute(self, context):
            self.report({'INFO'}, "Hello world!")
            return {'FINISHED'}
 
    
    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.label(text="Exploded Bake", icon='WORLD_DATA')
        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")
        row = layout.row()
        row.operator("object.simple_operator")


def register():
    bpy.utils.register_class(ExplodedBake)




def unregister():
    bpy.utils.unregister_class(ExplodedBake)




if __name__ == "__main__":
    register()

Edit, also I have an issue with the code you provided earlier, How do you remove the buttons that it added to the 3d view? I’ve got like, 50 of the same button on the header bar of my 3D view and I dont know how to remove them :stuck_out_tongue: Please help

You placed the operator inside the panel class, that’s not allowed.

How do you remove the buttons that it added to the 3d view?

F8

Been playing with it for the past few hours, looking at examples etc. Can’t find where I’m going wrong. I’m getting an error now and I’m totally confused:
search for unknown operator “BUTTON_OT_explode”, “button.explode” rna_uiItem0: operator missing srna “button.explode”

No idea where the BUTTON_OT_explode came from!

Heres my latest code:


bl_info = {
    "name": "Exploded Bake",
    "category": "Render",
}


import bpy


class ExplodedBake(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Exploded Bake"
    bl_idname = "exploded_bake"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


    
    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.prop(obj, "name")
        row = layout.row()
        row.operator("button.explode")
        
class buttonExplode(bpy.types.Operator):
    bl_idname = "button.explode"
    bl_label = "Button text"


    def execute(self, context):
        #self.report({'INFO'}, "Hello world!")
        print("hello")
        return {'FINISHED'}
        


        
def register():
    bpy.utils.register_class(ExplodedBake)




def unregister():
    bpy.utils.unregister_class(ExplodedBake)




if __name__ == "__main__":
    register()bl_info = {
    "name": "Exploded Bake",
    "category": "Render",
}


import bpy


class ExplodedBake(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Exploded Bake"
    bl_idname = "exploded_bake"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


    
    def draw(self, context):
        layout = self.layout
        obj = context.object
        row = layout.row()
        row.prop(obj, "name")
        row = layout.row()
        row.operator("button.explode")
        
class buttonExplode(bpy.types.Operator):
    bl_idname = "button.explode"
    bl_label = "Button text"


    def execute(self, context):
        #self.report({'INFO'}, "Hello world!")
        print("hello")
        return {'FINISHED'}
        


        
def register():
    bpy.utils.register_class(ExplodedBake)




def unregister():
    bpy.utils.unregister_class(ExplodedBake)




if __name__ == "__main__":
    register()

You need to register the operator as well.



def register():
    bpy.utils.register_class(ExplodedBake)
    bpy.utils.register_class(buttonExplode)

etc

Also look into naming conventions and I what you paste should be from two files.
Only one register function per file.
So with some cleanup you should be good to go.

Nicer formatted + 3 inline comments

bl_info = {
    "name": "Exploded Bake",
    "category": "Render",
}


import bpy


class ExplodedBake(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Exploded Bake"
    bl_idname = "OBJECT_PT_exploded_bake" # follow Blender convention for id names
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
    
    def draw(self, context):
        layout = self.layout
        obj = context.object
        
        row = layout.row()
        row.prop(obj, "name")
        
        row = layout.row()
        row.operator("button.explode")


class buttonExplode(bpy.types.Operator):
    bl_idname = "button.explode" # translates to C-name BUTTON_OT_explode
    bl_label = "Button text"

    def execute(self, context):
        #self.report({'INFO'}, "Hello world!")
        print("hello")
        return {'FINISHED'}
    
    
# (un-)register entire module, so you don't need to add every class here...
def register():
    bpy.utils.register_module(__name__)


def unregister():
    bpy.utils.unregister_module(__name__)


if __name__ == "__main__":
    register()

Ooooh totally awesome! Thanks guys. I think I was confused with the whole registering thing. It makes sense now. I registered the class of the new button I made and it now works as expected.

And thanks CoDEmanx for the tip about registering the whole module. Could you explain what you mean by “translates to C-name BUTTON_OT_explode” ?

Operator notation in C code is CATEGORY_OT_name_in_snake_case (OT stands for operator type).

In scripts, a more pythonic naming style is used: category.name_in_snake_case

However, the python names are converted to the C-notation, button.explode ends up as bpy.types.BUTTON_OT_explode

I see! Thanks for the explanation