14
$\begingroup$

I have try to make an UI Panel with my operator, but i can not create a panel with the 2 choices (axis and widht).

I can create a button who launch a menu in the tools pannel, and the operator works fine with this :

layout = self.layout
layout.operator(ChooseAxis.bl_idname)

But i want to have exactly this menu in the UI panel, not in tools, so I have try to write this :

layout.prop(obj, "axis")
layout.prop(obj, "newdim")

But that doesn't works, values ​​are modifiable but are ignored and do not modify the object.

How can i have the operator directly on the UI Panel ? (Not a button to launch the operator, but the operator himself with its Properties.)

Moreover, how i can keep the object size value when i launch the operator ? Because when i launch it, it the default value of the newdim property is set to 1 (for example), the object is directly resized. Is it possible to have a default="object actual value" ?

here the entire script with the ui panel created :

from bpy import *
import bpy
from bpy.props import FloatProperty, EnumProperty

class ProportionalDimensions(bpy.types.Panel):
    """Creates a Panel in the Object UI window"""
    bl_label = "Proportional Dimensions"
    bl_idname = "prop_dim"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    #bl_context = "object"
    
    def draw(self, context):
        obj = context.object
    
        #row = layout.row()
        #row.label(text="Active object is: " + obj.name)
  
        layout = self.layout
        layout.operator(ChooseAxis.bl_idname)

        layout.prop(obj, "axis")
        layout.prop(obj, "newdim")


class ChooseAxis(bpy.types.Operator):
    bl_idname = "object.choose_axis"
    bl_label = "Choose_the_Right_Axis"
    bl_description = "This is to choose the axis"
    bl_options = {'REGISTER', 'UNDO'}

    axis: EnumProperty(
        name="Axis",
        description="Axis selection",
        items= [('x', "X", ""),('y', "Y", ""),('z', "Z","")],
        default='x'
        )

    newdim: FloatProperty(
        name="Width",
        description="Scale",
        min=0.01, max=100.0,
        default=1,
        )
    # your code
    def scale(self, axis, new_dim):
        ob = bpy.context.active_object
        d = ob.dimensions

        x = d[0]
        y = d[1]
        z = d[2]

        scale =  axis

        if( scale == "x"):
            indice = 0
        elif( scale == "y"):
            indice = 1
        else:
            indice = 2

        old_dim = d[indice] 
        factor = new_dim / old_dim

        scale_x = ob.scale[0]
        scale_y = ob.scale[1]
        scale_z = ob.scale[2]

        ob.scale[0] = scale_x * factor
        ob.scale[1] = scale_y * factor
        ob.scale[2] = scale_z * factor

def execute(self, context):
    self.scale(self.axis,self.newdim)
    return {'FINISHED'}

def register():
    bpy.utils.register_class(ProportionalDimensions)
    bpy.utils.register_class(ChooseAxis)
   
    
def unregister():
    bpy.utils.unregister_class(ProportionalDimensions)
    bpy.utils.unregister_class(ChooseAxis)
    
if __name__ == "__main__":
    register()
$\endgroup$

1 Answer 1

21
$\begingroup$

You usually run an operator and adjust the settings afterwards in the Redo panel, or the operator should prompt the user before execution using invoke_props_dialog():

import bpy

class SimpleOperator(bpy.types.Operator):
    bl_label = "Simple Operator"
    bl_idname = "object.simple_operator"
    
    my_enum: bpy.props.EnumProperty(
        items=(
            ('ONE', "One", ""),
            ('TWO', "Two", ""),
            ('THREE', "Three", "")
        ),
        default='ONE'
    )
    
    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self)
    
    def execute(self, context):
        self.report({'INFO'}, self.my_enum)
        return {'FINISHED'}


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

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

if __name__ == "__main__":
    register()

    bpy.ops.object.simple_operator('INVOKE_DEFAULT')

If you really want to display UI elements in a panel to be set before clicking the button, you will have to register global properties and pass them to the according operator properties (you can't add operator properties to a panel).

import bpy

class SimpleOperator(bpy.types.Operator):
    bl_label = "Simple Operator"
    bl_idname = "object.simple_operator"
    
    my_enum: bpy.props.EnumProperty(
        items=(
            ('ONE', "One", ""),
            ('TWO', "Two", ""),
            ('THREE', "Three", "")
        ),
        default='ONE'
    )
    
    def execute(self, context):
        self.report({'INFO'}, self.my_enum)
        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

        ob = context.object

        row = layout.row()
        row.prop(ob, "my_global_enum", expand=True)
        
        props = layout.operator(SimpleOperator.bl_idname)
        props.my_enum = ob.my_global_enum


def register():
    bpy.utils.register_class(SimpleOperator)
    bpy.utils.register_class(HelloWorldPanel)
    
    bpy.types.Object.my_global_enum = bpy.props.EnumProperty(
        items=(
            ('ONE', "One", ""),
            ('TWO', "Two", ""),
            ('THREE', "Three", "")
        ),
        default='TWO'
    )


def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)
    bpy.utils.unregister_class(SimpleOperator)
    del bpy.types.Object.my_global_enum


if __name__ == "__main__":
    register()
$\endgroup$
6
  • $\begingroup$ Thank you, the first way works fine and launch au modal. But the second way doesn't works. I post a new question with the second method transpose in my case. $\endgroup$
    – Fabrice
    Oct 13, 2014 at 12:42
  • 1
    $\begingroup$ You can set a default value for the global property, but you can't really base it on another property, because you can't access the context at registration time of an addon (it will work for scripts you run via the text editor however) $\endgroup$
    – CodeManX
    Oct 13, 2014 at 12:56
  • $\begingroup$ Note that you can use a PointerProperty instead of creating each property separately. See blender.stackexchange.com/questions/6975/… $\endgroup$
    – Cobertos
    Sep 13, 2015 at 6:13
  • 1
    $\begingroup$ I'm not sure what you mean, you still need to register individual properties. A pointer property helps to organize them to avoid name conflicts. $\endgroup$
    – CodeManX
    Sep 13, 2015 at 9:13
  • 1
    $\begingroup$ Great, thanks! Do you know why you can't add operator properties to a panel? $\endgroup$ Apr 23, 2022 at 18:11

You must log in to answer this question.

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