many questions about layout

I’m kinda stuck right now in development in the LAYOUT :frowning: :frowning:

as I understand every layout Button needs to call an Operator

now what I got:
my HUGE function that will need to take the data from Buttons

now what I need:
how to convert the function to Operator,then call parts of that Operator into the Layout!!

so please in the answer make something that I expect:
a Button that specifies a custom value (which will read into my function)

I need something as complicated as BOIDS layout!!

Here is a combination of the SimpleOperator and the SimplePanel from the templates of the script editor.


import bpy

from bpy.props import IntProperty, FloatProperty, StringProperty, BoolProperty

def main(context):
    for ob in context.scene.objects:
        print(ob)

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

    my_value = bpy.props.StringProperty(default = "NA")
    
    @classmethod
    def poll(cls, context):
        return context.active_object is not None

    def execute(self, context):
        print(self.my_value)
        #main(context)
        return {'FINISHED'}

class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"

    def draw(self, context):
        layout = self.layout

        layout.operator("object.simple_operator", icon="ZOOMIN", text="Hello").my_value = "Hello"
        layout.operator("object.simple_operator", icon="ZOOMOUT", text="World").my_value = "World"


def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)


def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.utils.unregister_class(HelloWorldPanel)

if __name__ == "__main__":
    register()


Each button passes a different value to the same operator.

thank you a lot for this help :smiley:
I understand almost everything here,but some questions to understand"more"

the part: def main
and the other part: @classmethod --> def poll,def execute

In this example, main is just any def that you want to use for execution. You don’t have to have a main, I have commented it out and just issue a print. Poll and execute are required to make the operator run. I am not sure about the class decorator. I believe that is pure python and not Blender specific.

classmethod / staticmethod decorator is important here as you don’t have a class instance at the time poll() is called, self.poll() would only be possible if there was already. But since it is called to check whether an operator instance can be created in current context or not, it has to be made available by turning it into a classmethod / staticmethod.

well thanks a lot for the info :smiley:
as I came from C++ background,I always compare Python to C++(they “look” the same in the workflow) but in reality Python is easier,error pruner!! (as in C++ you can control data types,pointers)
about the classmethod,I think it is something like initialize for the class?or is it like forward declaration?

ah I read more now about decorators
as this decorator takes a function (from the tutorial) so I guess it is identical to <Template> in C++
which compiles and defines the data type at run time (same for classes too)

well one last question as I began in the layout work
what I’m doing is like 10 sliders to determine input values
after that will be a Big Button to do execution of my function with these input data

how to do something like this,as when I tested with multiple buttons each button “as done in this example” reads a single value as input

conclusion:
I only want to execute with a single Button that reads from a whole bunch of another sliders

Hm no I don’t think so. Datatypes don’t really matter in python. Decorators rather wrap the following function, so you can run code before that function and after execution, but all you need to do is calling that function, and not another utility function / wrapper. @staticmethod and @classmethod are special afaik, it’s like putting a “static” in front of a C++ class method, or like calling TheClass::method() instead of TheClass->method()

I only want to execute with a single Button that reads from a whole bunch of another sliders

Is it always the same amount of sliders? Or are they dynamically added, do they depend on selection etc.?

lets assume first they are the same amount of sliders :slight_smile:

I may need (but don’t know how) to add a dynamic list like BOIDS brain list,but afaik of that let me understand first how to do the easy part of UI

import bpy

# ExportHelper is a helper class, defines filename and
# invoke() function which calls the file selector.
from bpy_extras.io_utils import ExportHelper
from bpy.props import StringProperty, BoolProperty, IntProperty
from bpy.types import Operator




class ExportSomeData(Operator, ExportHelper):
    """This appears in the tooltip of the operator and in the generated docs"""
    bl_idname = "export_test.some_data"  # important since its how bpy.ops.import_test.some_data is constructed
    bl_label = "Export Some Data"


    # ExportHelper mixin class uses this
    filename_ext = ".txt"


    filter_glob = StringProperty(
            default="*.txt",
            options={'HIDDEN'},
            )


    # List of operator properties, the attributes will be assigned
    # to the class instance from the operator settings before calling.
    slider1 = IntProperty(
            name="One",
            description="Example Tooltip",
            min=0, max=12,
            default=6
            )
    slider2 = IntProperty(
            name="Two",
            description="Example Tooltip",
            min=-10, max=10
            )
    slider3 = IntProperty(
            name="Three",
            description="Example Tooltip",
            soft_min=-20, soft_max = 20
            )
    slider4 = IntProperty(
            name="Four",
            description="Example Tooltip",
            min=500, max=5000,
            subtype="FACTOR"
            )
            
    def draw(self, context):
        layout = self.layout
        layout.label("Sliders:")
        layout.prop(self, "slider1")
        layout.prop(self, "slider2")
        layout.prop(self, "slider3", slider=True)
        layout.prop(self, "slider4", text="New name")




    def execute(self, context):
        print()
        print("Properties:")
        for prop in self.properties.keys():
            print(prop, "=", self.properties[prop])
        # or simpler like:
        #print(self.slider1)
        return {'FINISHED'}




# Only needed if you want to add into a dynamic menu
def menu_func_export(self, context):
    self.layout.operator(ExportSomeData.bl_idname, text="Text Export Operator")




def register():
    bpy.utils.register_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.append(menu_func_export)




def unregister():
    bpy.utils.unregister_class(ExportSomeData)
    bpy.types.INFO_MT_file_export.remove(menu_func_export)




if __name__ == "__main__":
    register()


    # test call
    bpy.ops.export_test.some_data('INVOKE_DEFAULT')

well this example helped me a lot to understand more about layouts :smiley:
but one question about it as I may need it in “specifying a folder for the obj generation”

to be clear on my workflow as I don’t export data like this :slight_smile:
I will take the whole data from the buttons (sliders) when they click for example the master button(for example called"generate mesh"))

how I take data?I think I understand now how to get the data :smiley:
I just will pass the data to my function and then export them with ctypes to my .DLL,then I know my way inside C++ :slight_smile:

the question now:
1-I don’t see the space type where the export space appeared from
2-how to"catch" the name(full path + name) so I pass it too like other sliders

1 - have a look at bpy_extras\io_utils.py::ExportHelper, there’s your magic :wink:
2 - what paths? There’s the filepath, but passing to other sliders?!

1-I will look at it tonight
2-I will just take the user defined path + data from sliders and pass them to my function :smiley:

I think I’m close :slight_smile:

well I tried to mix everything here,but it fails with the sliders :frowning:


import bpy


from bpy.props import IntProperty, FloatProperty, StringProperty, BoolProperty


def main(context):
    for ob in context.scene.objects:
        print(ob)


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


    my_value = bpy.props.StringProperty(default = "NA")
    my_float = bpy.props.FloatProperty(default = 0.0)


    slider1 = IntProperty(name="One", description="Example Tooltip", min=0, max=12, default=6)
            
    slider2 = IntProperty(name="Two", description="Example Tooltip", min=-10, max=10)
            
    slider3 = IntProperty(name="Three", description="Example Tooltip", soft_min=-20, soft_max = 20)
            
    slider4 = IntProperty(name="Four", description="Example Tooltip", min=500, max=5000, subtype="FACTOR")
                
    @classmethod
    def poll(cls, context):
        return context.active_object is not None


    def execute(self, context):
        print(self.my_value)
        print(self.my_float)
        #main(context)
        return {'FINISHED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"
    
    def draw(self, context):
        layout = self.layout


        layout.operator("object.simple_operator", icon="ZOOMIN", text="Hello").my_value = "Hello"
        layout.operator("object.simple_operator", icon="ZOOMOUT", text="World").my_value = "World"
        layout.operator("object.simple_operator", icon="ZOOMIN", text="float").my_float = -1.0       
        props = layout.operator("object.simple_operator")
        props.my_value = "Hello"
        props.my_float = 5.0
                    
        layout.label("Sliders:")
        layout.prop(self, "slider1")
        layout.prop(self, "slider2")
        layout.prop(self, "slider3", slider=True)
        layout.prop(self, "slider4", text="New name")       




def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)




def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()

here is the error
\Text:54
rna_uiItemR: property not found: OBJECT_PT_hello.slider2

\Text:55
rna_uiItemR: property not found: OBJECT_PT_hello.slider3

\Text:56
rna_uiItemR: property not found: OBJECT_PT_hello.slider4

\Text:57
rna_uiItemR: property not found: OBJECT_PT_hello.slider1

Remember, self, in this case, is the self of the Panel, not the operator. That is why the properties are not found. To use layout in this manner, the properties would have to belong to the object because your are in the object context when you reference the self.

I kinda understand what you mean,so you mean I put the whole stuff in the operator?

I couldn’t figure out how to fix this problem …
kinda lost again :smiley:

well I got it working!!
but tell me if this is the correct way


import bpy


from bpy.props import IntProperty, FloatProperty, StringProperty, BoolProperty


def main(context):
    for ob in context.scene.objects:
        print(ob)


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


    my_value = bpy.props.StringProperty(default = "NA")
    
    
    @classmethod
    def poll(cls, context):
        return context.active_object is not None


    def execute(self, context):
        print(self.my_value)
        #main(context)
        return {'FINISHED'}


class HelloWorldPanel(bpy.types.Panel):
    """Creates a Panel in the Object properties window"""
    bl_label = "Hello World Panel"
    bl_idname = "OBJECT_PT_hello"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "object"


    
            
    def draw(self, context):
        scn = bpy.context.scene
        layout = self.layout


        layout.operator("object.simple_operator", icon="ZOOMIN", text="Hello").my_value = "Hello"
        layout.operator("object.simple_operator", icon="ZOOMOUT", text="World").my_value = "World"
                    
        layout.label("Sliders:")
        layout.prop(scn, "slider1")
        layout.prop(scn, "slider2")
        layout.prop(scn, "slider3", slider=True)
        layout.prop(scn, "slider4", text="New name")  
        
                        
    @classmethod
    def poll(cls, context):
        return context.active_object is not None


    def execute(self, context):
        print(self.my_value)
        print(self.my_float)
        #main(context)
        return {'FINISHED'}
 




def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)




def unregister():
    bpy.utils.unregister_class(SimpleOperator)
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()
    
    scn = bpy.types.Scene
    
    scn.slider1 = IntProperty(
            name="One",
            description="Example Tooltip",
            min=0, max=12,
            default=6
            )
    scn.slider2 = IntProperty(
            name="Two",
            description="Example Tooltip",
            min=-10, max=10
            )
    scn.slider3 = IntProperty(
            name="Three",
            description="Example Tooltip",
            soft_min=-20, soft_max = 20
            )
    scn.slider4 = IntProperty(
            name="Four",
            description="Example Tooltip",
            min=500, max=5000,
            subtype="FACTOR"
            )