3

I'm trying to combine Render-Presets with Camera-Presets. Why is this script causing an Error? What does it mean: "Python: Traceback (most recent call last): File "C:\Program Files\Blender Foundation\Blender 2.91\2.91\scripts\startup\bl_operators\presets.py", line 166, in execute exec(rna_path) File "", line 1, in AttributeError: 'NoneType' object has no attribute 'data'

location: :-1 " ?

This Error is coming also if a Camera is selected.

How can I make it work?

Here is the script:

import bpy
from bpy.types import Operator, Menu
from bl_operators.presets import AddPresetBase

class OBJECT_MT_display_presets(Menu): bl_label = "Object Display Presets" preset_subdir = "object/display" preset_operator = "script.execute_preset" draw = Menu.draw_preset

class AddPresetObjectDisplay(AddPresetBase, Operator): '''Add a Object Display Preset''' bl_idname = "camera.object_display_preset_add" bl_label = "Add Object Display Preset" preset_menu = "OBJECT_MT_display_presets"

# variable used for all preset values
preset_defines = [
    "render  = bpy.context.scene.render",
    "data = bpy.context.object.data"
]

# properties to store in the preset
preset_values = [
    "render.engine",
    "render.use_stamp",
    "data.cycles.fisheye_lens",
    "data.cycles.fisheye_fov",
    "data.shift_x",
    "data.shift_y"

]

# where to store the preset
preset_subdir = "Test_Folder"


Display into an existing panel

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

row = layout.row(align=True)
row.menu(OBJECT_MT_display_presets.__name__, text=OBJECT_MT_display_presets.bl_label)
row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_IN')
row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_OUT').remove_active = True


classes = ( OBJECT_MT_display_presets, AddPresetObjectDisplay, )

def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.RENDER_PT_context.prepend(panel_func)

def unregister(): for cls in classes: bpy.utils.unregister_class(cls) bpy.types.RENDER_PT_context.remove(panel_func)

if name == "main": register()

Andi
  • 741
  • 3
  • 11

1 Answers1

3

Use context.active_object

The issue, re that error message in question, is with the preset operator in question is it is recognizing only context.active_object rather than context.object, which it sees as None. Perhaps context.object is used for the pinid object if set, where there is a pin object. Test

context.scene.camera

Anyhow, for the context members being set we can instead look at the scene camera. Have added a poll method to the operator to have it only poll when the render engine is cycles and the scene has a camera.

Otherwise change poll such that, in addition to being cycles render engine

ob = context.object
return ob and ob.type == 'CAMERA' and ...

and in preset

"camera = bpy.context.active_object.data"

Made the preset_subdir same in menu and operator. Another mixin class could be used for this.

Wrapped the base class menu draw method into draw. This way can append prepend a menu item.

Only enabled preset row when it polls to avoid trying to save / set when not polling.

import bpy
from bpy.types import Operator, Menu
from bl_operators.presets import AddPresetBase

class OBJECT_MT_display_presets(Menu): bl_label = "Object Display Presets" preset_subdir = "Test_Folder" preset_operator = "script.execute_preset" #draw = Menu.draw_preset def draw(self, context): self.draw_preset(context)

class AddPresetObjectDisplay(AddPresetBase, Operator): '''Add a Object Display Preset''' bl_idname = "camera.object_display_preset_add" bl_label = "Add Object Display Preset" preset_menu = "OBJECT_MT_display_presets"

# variable used for all preset values
preset_defines = [
    "scene  = bpy.context.scene",
    "render = scene.render",
    "camera = scene.camera.data",
]

# properties to store in the preset
preset_values = [
    "render.engine",
    "render.use_stamp",
    "camera.cycles.fisheye_lens",
    "camera.cycles.fisheye_fov",
    "camera.shift_x",
    "camera.shift_y"

]

# where to store the preset
preset_subdir = "Test_Folder"
@classmethod
def poll(cls, context):
    scene = context.scene
    return (
            scene.camera
            and scene.render.engine == 'CYCLES'
            )

Display into an existing panel

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

row = layout.row(align=True)
row.enabled =  bpy.ops.camera.object_display_preset_add.poll()

row.menu(OBJECT_MT_display_presets.__name__, text=OBJECT_MT_display_presets.bl_label)

row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_IN')
row.operator(AddPresetObjectDisplay.bl_idname, text="", icon='ZOOM_OUT').remove_active = True


classes = ( OBJECT_MT_display_presets, AddPresetObjectDisplay, )

def register(): for cls in classes: bpy.utils.register_class(cls) bpy.types.RENDER_PT_context.prepend(panel_func)

def unregister(): for cls in classes: bpy.utils.unregister_class(cls) bpy.types.RENDER_PT_context.remove(panel_func)

if name == "main": register()

Can Python Operator Presets be shared between Operators?

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • Thank you so much batFINGER! Now it works everything fine. And finally I can release my first Addon. Hurray :D – Andi Jan 29 '21 at 15:49