2
$\begingroup$

Trying to make something like a clothing manager addon for myself. Easy to add, enable and disable objects. I'm not sure if this is the right way, because I can't get which button is pressed. But I don't even know what exactly I should be looking at to solve this.

draw:

    def draw(self, context):
    layout = self.layout
    scene = context.scene
    col = layout.column(align=False)

    layout.operator( "add.select")
    
    layout.label(text=" Outfit List:")
    SCENE_OBJ = bpy.context.scene.objects
    for tmp_obj in SCENE_OBJ:
        if tmp_obj.type == 'MESH':
            if ".mf1t." in tmp_obj.name:
                if ".mf1t.active" in tmp_obj.name:
                    layout.operator("on.off", text=tmp_obj.data.name, text_ctxt='hoho', depress=True)
                if ".mf1t.null" in tmp_obj.name:
                    layout.operator("on.off", text=tmp_obj.data.name, text_ctxt='haha', depress=False)

operator:

class op_add (bpy.types.Operator):
bl_idname = "add.select"
bl_label = "Add to List"

def execute(self, context):
    CS_OBJ = bpy.context.selected_objects
    
    for tmp_obj in CS_OBJ:
        if tmp_obj.type == 'MESH':
            if ".mf1t." not in tmp_obj.name:
                tmp_obj.name = tmp_obj.name + ".mf1t.active"

class op_on_off (bpy.types.Operator):
bl_idname = "on.off"
bl_label = "On / Off"

def execute(self, context):
    if context.window_manager:
        if ".mf1t.active" in tmp_obj.name:
            tmp_obj.name = tmp_obj.name.replace("active", "null")
        if ".mf1t.null" in tmp_obj.name:
            tmp_obj.name = tmp_obj.name.replace("null", "active")

--------------------------------------------------------------------

I'll post my result here. Perhaps this will help someone, but Marty answer is already pretty clear. Result (Thank to Marty Fouts):

bl_info = {
    "name" : "On/Off Manager Explain",
    "description" : "A demonstration addon (https://blender.stackexchange.com/questions/252081/create-buttons-from-the-objects-with-same-action-for-each-of-them-get-name-pre)",
    "author" : "Marty Fouts and duales",
    "version" : (1, 0, 0),
    "blender" : (2, 80, 0),
    "location" : "View3D",
    "warning" : "",
    "support" : "COMMUNITY",
    "doc_url" : "https://blender.stackexchange.com/questions/252081/create-buttons-from-the-objects-with-same-action-for-each-of-them-get-name-pre",
    "category" : "3D View"
}

import bpy
from bpy.types import Operator
from bpy.types import Panel
from bpy.props import StringProperty

class op_add_exp(Operator):
    bl_idname = "op.add"
    bl_label = "Add to Global"
    bl_options = {"REGISTER", "UNDO"}

    def execute(self, context):
        for tmp_obj in bpy.context.selected_objects:
            if tmp_obj.type == 'MESH':
                if ".mf1t." not in tmp_obj.name:
                    tmp_obj.name = tmp_obj.name + ".mf1t.active"

        return {'FINISHED'}

class op_on_off_exp(Operator):
    """ tooltip goes here """
    bl_idname = "op.on_off"
    bl_label = "Foo Operator"
    bl_options = {"REGISTER", "UNDO"}
    
    foo : StringProperty(name="foo", description="foobar")
    
    @classmethod
    def poll(cls, context):
        return context.mode == "OBJECT"
    
    def execute(self, context):
        for tmp_obj in bpy.context.scene.objects:
            if ".mf1t.active" in tmp_obj.name:
                if tmp_obj.name == self.foo:
                    tmp_obj.name = tmp_obj.name.replace("active", "null")
                    tmp_obj.hide_viewport = True
                    tmp_obj.hide_render = True
            elif ".mf1t.null" in tmp_obj.name:
                if tmp_obj.name == self.foo:
                    tmp_obj.name = tmp_obj.name.replace("null", "active")
                    tmp_obj.hide_viewport = False
                    tmp_obj.hide_render = False

        return {'FINISHED'}

class panel_manager_exp(Panel):
    """Display test button twice. Invoke it with different arguments"""
    bl_label = "On/Off Manager Exp"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Item"

    def draw(self, context):
        self.layout.operator(op_add_exp.bl_idname, text="Add Selected OBJ")
        self.layout.label(text="Added Object List")
        col = self.layout.column(align=True)
        for tmp_obj in bpy.context.scene.objects:
            if tmp_obj.type == 'MESH':
                if ".mf1t." in tmp_obj.name:
                    if ".mf1t.active" in tmp_obj.name:
                        prop = col.operator(op_on_off_exp.bl_idname, text=tmp_obj.data.name, depress=True).foo=tmp_obj.name
                    if ".mf1t.null" in tmp_obj.name:
                        prop = col.operator(op_on_off_exp.bl_idname, text=tmp_obj.data.name, depress=False).foo=tmp_obj.name

classes = [
    op_on_off_exp,
    op_add_exp,
    panel_manager_exp,
]

def register():
    for c in classes:
        bpy.utils.register_class(c)

def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)

if __name__ == '__main__':
    register()

And in the end you will be able to do something like this. Simple but convenient. enter image description here

$\endgroup$
0

2 Answers 2

3
$\begingroup$

If you want a single operator to respond differently to different buttons, one way to do this is to give the operator a class variable. Then, when you create the buttons in the panel, you set the class variable. This example adds a variable foo to a simple operator class and then calls the class execute function through the panel with bar or hah depending on which button is pushed in the panel. It takes advantage of the fact that the UI operator function returns a pointer to the operator's data and Python syntax allows the pointer to be used at the call site. In this example the execute routine just prints the value of foo. You can use it how you would like.

import bpy

bl_info = {
    "name" : "multiple buttons",
    "description" : "A demonstration addon",
    "author" : "Marty",
    "version" : (0, 0, 1),
    "blender" : (2, 80, 0),
    "location" : "View3D",
    "warning" : "",
    "support" : "COMMUNITY",
    "doc_url" : "",
    "category" : "3D View"
}

import bpy
from bpy.types import Operator
from bpy.types import Panel
from bpy.props import StringProperty


class TLA_OT_operator(Operator):
    """ tooltip goes here """
    bl_idname = "demo.operator"
    bl_label = "I'm a Skeleton Operator"
    bl_options = {"REGISTER", "UNDO"}
    
    foo : StringProperty(name="foo", description="foobar")

    @classmethod
    def poll(cls, context):
        return context.mode == "OBJECT"

    def execute(self, context):

        self.report({'INFO'},
            f"execute() foo = {self.foo}")

        return {'FINISHED'}


class TLA_PT_sidebar(Panel):
    """Display test button twice. Invoke it with different arguments"""
    bl_label = "buttons"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "TLA"

    def draw(self, context):
        col = self.layout.column(align=True)
        prop = col.operator(TLA_OT_operator.bl_idname, text="This is bar").foo="bar"
        prop = col.operator(TLA_OT_operator.bl_idname, text="This is hah").foo="hah"
 
classes = [
    TLA_OT_operator,
    TLA_PT_sidebar,
]

def register():
    for c in classes:
        bpy.utils.register_class(c)


def unregister():
    for c in classes:
        bpy.utils.unregister_class(c)


if __name__ == '__main__':
    register()
$\endgroup$
4
  • $\begingroup$ foo is a class member (or member variable, not just a variable), in this case a string property. $\endgroup$
    – pyCod3R
    Commented Jan 29, 2022 at 17:44
  • 1
    $\begingroup$ Yes, I said that. Perhaps too indirectly, but "you give the operator a class variable" and "adds a variable foo to..." implies that foo is a class variable in an operator class. Still I can make it clearer. $\endgroup$ Commented Jan 29, 2022 at 17:52
  • 1
    $\begingroup$ Thank You so much. <3 I already did something similar with enum, but enum is not so convenient to use. That solve all what i try to do. $\endgroup$
    – duales
    Commented Jan 29, 2022 at 20:08
  • $\begingroup$ I'm glad I was able to help. I look forward to seeing what you accomplish. $\endgroup$ Commented Jan 29, 2022 at 20:09
0
$\begingroup$

Here is an example of what you want to do. I "stole" it from here: https://b3d.interplanety.org/en/calling-functions-by-pressing-buttons-in-blender-custom-ui/

bl_info = {
  "name": "Multiple operator example",
  "author": "Ibraheem",
  "version": (1, 0),
  "blender": (2, 80, 0),
  "location": "View3D > Sidebar > My own addon",
  "description": "Example with multiple operators",
  "warning": "",
  "wiki_url": "",
  "category": "3D View"}
 
import bpy
 
 
class EXAMPLE_OT_func_1(bpy.types.Operator):
  bl_idname = "do.func_1"
  bl_label = "Lay Ground"
 
  def execute(self, context):
    # Implement your first function here
    self.report({'INFO'}, f"This is {self.bl_idname}")
    bpy.ops.mesh.primitive_plane_add(size=2, enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
    return {'FINISHED'}
 
 
class EXAMPLE_OT_func_2(bpy.types.Operator):
  bl_idname = "example.func_2"
  bl_label = "Function 2"
 
  def execute(self, context):
    # Implement your second function here
    self.report({'INFO'}, f"This is {self.bl_idname}")
    return {'FINISHED'}
 
 
class Function3_delete_selected_object(bpy.types.Operator):
  bl_idname = "do.delete_obj"
  bl_label = "Function 3"
 
  def execute(self, context):
    # Implement your third function here
    obj = context.active_object
    bpy.data.objects.remove(obj)
    self.report({'INFO'}, f"This is {self.bl_idname}")
    return {'FINISHED'}
 
 
class EXAMPLE_PT_panel(bpy.types.Panel):
  bl_label = "MAP MAKER"
  bl_category = "M_M"
  bl_space_type = "VIEW_3D"
  bl_region_type = "UI"
 
  def draw(self, context):
    layout = self.layout     
    obj=context.active_object
    if obj:
      layout.row().label(text="Active object is: " + obj.name)
      layout.row().prop(obj, "name")
    layout.operator(EXAMPLE_OT_func_1.bl_idname)
    layout.operator(EXAMPLE_OT_func_2.bl_idname)
    layout.operator(Function3_delete_selected_object.bl_idname)
 
     
 
 
classes = (EXAMPLE_OT_func_1, EXAMPLE_OT_func_2, Function3_delete_selected_object, EXAMPLE_PT_panel)
 
 
def register():
  for cls in classes:
    bpy.utils.register_class(cls)
 
 
def unregister():
  for cls in classes:
    bpy.utils.unregister_class(cls)
 
 
if __name__ == "__main__":
  register()
$\endgroup$
1
  • $\begingroup$ It's not what the OP should do. It's not even the solution to what they are trying to do, which is to have a single operator that is informed of which button was pressed. $\endgroup$ Commented Jan 29, 2022 at 17:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .