gordon13
(gordon13)
July 22, 2014, 4:50pm
1
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
CoDEmanX
(CoDEmanX)
July 22, 2014, 5:40pm
2
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!
gordon13
(gordon13)
July 23, 2014, 12:43pm
3
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 Please help
CoDEmanX
(CoDEmanX)
July 23, 2014, 3:39pm
4
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
gordon13
(gordon13)
July 23, 2014, 4:31pm
5
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()
Linusy
(Linusy)
July 24, 2014, 12:44am
6
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.
CoDEmanX
(CoDEmanX)
July 24, 2014, 10:06am
7
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()
gordon13
(gordon13)
July 24, 2014, 4:22pm
8
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” ?
CoDEmanX
(CoDEmanX)
July 24, 2014, 5:26pm
9
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
gordon13
(gordon13)
July 25, 2014, 4:33am
10
I see! Thanks for the explanation