I want to be able to have an operator with a property:
class VS_OT_Select(bpy.types.Operator):
#...
extend = bpy.props.BoolProperty(...)
def execute(self, context):
#...
And a panel with a button for the operator as well as setting the properties themselves:
class VS_PT_MyPanel(bpy.types.Panel):
#...
def draw(self, context):
layout = self.layout
scene = context.scene
op = layout.operator(VS_OT_Select.bl_idname)
layout.prop(op, 'extend')
# or
op.draw() # and I expose the properties myself
I keep getting attribute not found errors however I do it. I know properties can be drawn/exposed during a redo and after the operator is run. I also know I can create global scene variables to be referenced by the operator - that’s what I currently am doing - but I have lots of variables and I’d like to keep the addon’s register() clean. I’d like to be able to expose the operators properties in a UI panel beforehand so users can tweak before running. Is this possible within Blender at this point (2.9x)?
However, this still doesn’t answer the base question for me: is there a reason why operator properties cannot be accessed and edited directly in a UI panel yet, for architecture reasons perhaps?
Thank you for posting. I definitely like the organization of grouping them into a PointerProperty by operator over registering each prop by itself in register(). That will definitely be useful to others.
I still wish the higher goal is attainable of keeping property declarations within the operator. In other words, all props the operator needs are completely self-contained, and panels simply access the operator’s props directly for the user to tweak.
To extend this script we’re chaining, here’s my ideal:
import bpy
#Panel for operator
class VIEW3D_PT_custom_panel(bpy.types.Panel):
bl_label = "Custom Panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "Tool"
@classmethod
def poll(cls, context):
return (context.object is not None)
def draw(self, context):
layout = self.layout
op = layout.operator("object.simple_operator", text="Execute Simple Operator")
layout.prop(op, 'location')
layout.prop(op, 'hidden')
#Object simple operator
class OBJECT_OT_simple_operator(bpy.types.Operator):
bl_idname = "object.simple_operator"
bl_label = "Simple Object Operator"
bl_options = {'REGISTER', 'UNDO'}
location: bpy.props.FloatVectorProperty(name="Location", size=3)
hidden: bpy.props.BoolProperty(name="Hidden")
def execute(self, context):
context.object.location = self.location
context.object.hide_set(self.hidden)
return {'FINISHED'}
classes = (
VIEW3D_PT_custom_panel,
OBJECT_OT_simple_operator,
)
def register():
from bpy.utils import register_class
for cls in classes:
register_class(cls)
def unregister():
from bpy.utils import unregister_class
for cls in reversed(classes):
unregister_class(cls)
if __name__ == "__main__":
register()
These operator properties can be made visible to the user in the UI panel:
However, they’re not editable here - they’re locked. I can certainly edit the properties in the redo panel after I run them or as a developer set the settings within the panel (op.hidden = True). However, depending on the settings the user chooses, some operators may run for relatively long time. I’d prefer the user to get to adjust the settings in the panel first before running the operator.
I guess the big question is, why are operator props unable to be tweaked within a UI panel directly?
I ran into this very issue. It turns out that every time you move the mouse, etc, the panel is redrawn and that recreates the operator resetting the properties to their default. You need to store the properties elsewhere. I’m following this tutorial and it works though I feel there could be a better place to store the properties than scene.
I appreciate the explanation - that explains why exposing the operator settings seems “locked” on the panel. It’s just reset constantly. The keymap solution does get around this. My current solution is just to have the props dialog pop up so users can choose settings before it runs (there are cases where it can take a while, so I don’t want users to have to readjust and wait longer):
B.Y.O.B
(Node Preview and LuxCore Addon Developer)
7
As far as I understand it, an operator class is like a blueprint. There exists no instance of it until the operator is triggered by something, at which point Blender uses the blueprint to create the actual instance.
Also, the return value of layout.operator() is not an instance of the operator class. Instead, it’s an instance of OperatorProperties, which is later passed to the actual operator instance on creation.
Thank you for that - I marked your answer as a solution, coupled with the fact that the panel is redrawn constantly is why the properties reset. It’s a good foundation so others can understand why that is
I’d be curious to see if it makes sense for Blender to allow persisted operator-scope variables in panel layouts so they could be edited for an operator pre-execution (granted, my invoke solution is pretty close to that).