How to pass two arguments to a button operator

Hi!

I am looking at giving more than one arguments to a button operator. I know how to pass one. I create a property and assign a new value to it in the draw function of the panel. This is very useful because, one single operator can serve as many buttons. But what if I’d like to pass two arguments?

Here is a simplified example showing the situation.

import bpy



class SimpleOperator(bpy.types.Operator):
    ''''''
    bl_idname = "object.simple_operator"
    bl_label = ""
    
    property_1 = bpy.props.StringProperty() # defining the property
    property_2 = bpy.props.StringProperty() # defining another property
    
    def execute(self, context):
        print("property_1 :" + self.property_1)
        print("property_2 :" + self.property_2)
        return {'FINISHED'}


class OBJECT_PT_hello(bpy.types.Panel):
    bl_label = "Hello World Panel"
    bl_space_type = "PROPERTIES"
    bl_region_type = "WINDOW"
    bl_context = "object"

    def draw(self, context):
        layout = self.layout
        col = layout.column()
        
        a = "Argument a"
        b = "Argument b"
        
        col.operator("object.simple_operator", text="property_1 passing a").property_1 = a
        col.operator("object.simple_operator", text="property_1 passing b").property_1 = b # same operator with different argument
        
        col.operator("object.simple_operator", text="property_2 passing a").property_2 = a # how to pass both argument together?


This example code will put three buttons in an “Hello World Panel” in the properties window on the object tab. Pushing on these buttons will print value of (a) or (b). Pushing on the third will pass (a) to another property. Now, how would I do if I want to pass both arguments at the same time and print both arguments. They must stay different arguments (c = a + b and passing c as argument would not work).

I think that a possibility would be to make a CollectionProperty and passing a list instead, but I didn’t figure how to do it. I think that it would work.

So here is my question :

  • Is it possible to assign new values to more than one property on a button operator? (and if yes how)
  • If not, How do I set a CollectionProperty to pass a list to my button operator (in this example)

Thanks for any clue.

Oh! please!
I’m sure someone has a clue!

Ok I’ll clarify something. In the above script, in the line :

col.operator("object.simple_operator", text="property_1 passing a").property_1 = a

I pass the argument (a) to (property_1) when (simple_operator) is executed. Is it possible to pass an argument to (property_1) and another one to (property_2) at the same time?

If not, how do I make a collection property to pass a list in which I would put (a, b)?

Thanks again.

You can put the two strings in just one and use a separator character you decide.

ab=“Argument a.Argument b”
And ‘.’ would be the separator to search for and split the string in two strings.

well if theses are scene properties tehcnically speeking they are available everywhere

so why pass theses in the call just declare them at the scene level and you can access eveywhere!

happy 2.5

The problem Axon D mentions is something I’ve also experienced and I’d be interested in seeing a solution.

Stringing arguments together is a workaround that has limitations. It’s ok for strings, but doesn’t work for lists, dictionaries, etc.
Storing arguments as (scene/window manager) properties unnecessarily clutters blender and is the workaround I usually use. But it’s still a workaround.

You could try in those cases a string like this: “N, P1, P2, P3” where N is the number of arguments, in this case 3, and P1, P2, P3 are pointers to such global variables (lists, dictionaires…).

But I think this is a way of complicate the life yourself. If BlenderFoundation don’t want operators to have arguments just create a different operator for each case you need and read global variables or properties stored in the Scene as RickyBlender says. I asked Ton why operators have not arguments and he said that it was very debated. Probably more easy to code and not really life or death issue so they did the easy way.

I would like them to have arguments by the way.

More easy: Instead passing a string, pass a pointer to a global list. In that list you have (N, P1, P2,…)

I mean this:
b=1
string1=“b”
c=eval(string1)

so this is the way of passing a “pointer” in python using a string and eval() then to be able to use that “pointer”.
I agree pointer is a bad name for that, call it “passing a variable name and posterior reading with eval method” instead. I am just lazy in naming things.

Thanks for the replies. Now I have some solutions.

I think I’ll go with something similar to what Bao2 talked. This seems an interesting approach I didn’t think of. but I will avoid to use an eval() function. I read on this forum that eval() should be used as less as possible for security reasons. Malicious code can be hidden with that.

I think I’ll encode my arguments and decode them with the separator approach and adapt with if statements. This should do the trick for my situation. But I really hope that arguments are implemented into operators. This would really make things easier.

Bye the way, is there a possibility to make lists properties? Is CollectionProperty a kind of list property? I never used them. I am not sure what they are used for.

there are enumlist and collection list pointer !
but for only 2 vars not required i think!

you could pass lis tmay be
but i prefer Properties easier to access anywhere anyway!

happy 2.5

Thank you RickyBlender

I think I’ll have to familiarize with them.

see you!

I found it…

when you execute col.operator() function you get returned a pointer to operator button and then you modified one attribute in the same line…
for example:

col.operator(“operator”, text=“button_text”).property1 = 1

You need to assign returned from col.operator() to a variable, and then change its properties.
for example

button = col.operator(“operator”, text=“button_text”)
button.property1 = 1
button.property2 = True
button.property3 = ‘string’

not really following here

can you give a small operator example

thanks

eval() has only one letter different from evil() and should be considered like that.

Can’t you just pass a tuple?

question was
how to pass two arguments to a button operator

don’t see it here

I can see how to read the data from the button values parameters

another way would be to use global vars !

salut



bl_info = {
        "name": "Multi-param operator example",
        "description":"Passing multiple params to an operator",
        "category": "Development"
        }


import bpy


class TEST_OT_multiparam(bpy.types.Operator):
    bl_idname = "test.multiparam"
    bl_label = "multiparam test op"
    param_a = bpy.props.StringProperty()
    param_b = bpy.props.IntProperty()
    def execute(self,context):
        print("self.param_a:",self.param_a)
        print("self.param_b:",self.param_b)
        self.report({"INFO"},"%s %s"%(self.param_a,self.param_b))
        return {"FINISHED"}




class TEST_PT_multiparam(bpy.types.Panel):
    bl_label = "Testing 123"
    bl_space_type = "VIEW_3D"
    bl_region_type = "TOOLS"
    bl_category = "Examples"
    def draw(self,context):
        layout = self.layout
        op =  layout.operator("test.multiparam")
        op.param_a = "Hello World!"
        op.param_b = 42




def register():
    bpy.utils.register_module(__name__)


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




when starting script
I get invalid window error !

it looks like you can change properties after being defined!
interesting!

can this run without using it as an addon ?
I mean running it from text editor

thanks

If you want to run addon code from the editor, you have to explicitely call register() at the bottom of your script.