4
$\begingroup$

I want a self-updating dropdown list that changes the render engine to either Cycles or eevee.

enter image description here

The code for this works when it is written directly like this.

bpy.context.scene.render.engine = 'CYCLES'

bpy.context.scene.render.engine = 'BLENDER_EEVEE'

But If I try to put it in a dropdown list, it doesn't work. Am I doing something wrong?

The same dropdown list work for other settings like FPS or render formats, why isn't it working here?

import bpy

from bpy.types import (Panel,
                       Menu,
                       PropertyGroup,
                       )
                       
class MyProperties(bpy.types.PropertyGroup):

    my_enum0 : bpy.props.EnumProperty(
        name= "",
        description= "Change the render engine of the scene",
        items= [('OP1', "Cycles", "f"),
                ('OP2', "Eevee", "fg"),
        ],
        update=lambda self, context: bpy.ops.addonname.myop_operator00()
    )
    
class TestPanel(bpy.types.Panel):
    bl_label = "Quick Render Presets"
    bl_idname = "PT_TestPanel"  
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Example'
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool  
    
        rowAA = layout.row()
        rowAA.label(text= "Render Engine:")
        
        layout.prop(mytool, "my_enum0")

class RenderRender2(bpy.types.Operator):
    bl_label = "Render Engine"
    bl_idname = "addonname.myop_operator00"
        
    def execute(self, context):
        scene = context.scene
        mytool = scene.my_tool
        
        if mytool.my_enum == 'OP1':
            bpy.context.scene.render.engine = 'CYCLES'
                      
        if mytool.my_enum == 'OP2':
            bpy.data.scene.render.engine = 'BLENDER_EEVEE'

            
        return {'FINISHED'}
    
classes = [MyProperties, RenderRender2, TestPanel]
 
 
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
        
        bpy.types.Scene.my_tool = bpy.props.PointerProperty(type= MyProperties)
        
 
def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
        del bpy.types.Scene.my_tool
 
    
if __name__ == "__main__":
    register()
$\endgroup$
3
  • 2
    $\begingroup$ shouldn't it be mytool.my_enum0 ? Also why not simply writing layout.prop(context.scene.render, "engine") in the panel draw code ? $\endgroup$
    – Gorgious
    Commented Apr 3, 2022 at 15:44
  • 2
    $\begingroup$ In addition, if you replace OP1 and OP2 by CYCLES and BLENDER_EEVEE in the enum, you can replace the two if statements with bpy.context.scene.render.engine = mytool.my_enum and then you won't have to change the code if you add another render engine to the enum. $\endgroup$ Commented Apr 3, 2022 at 15:56
  • $\begingroup$ Thank you, both of you $\endgroup$ Commented Apr 3, 2022 at 16:08

2 Answers 2

1
$\begingroup$

2 mistakes:

1 -> comment of Gorgious

2 ->

 if mytool.my_enum == 'OP1':
        bpy.context.scene.render.engine = 'CYCLES'
                  
 if mytool.my_enum == 'OP2':
        bpy.data.scene.render.engine = 'BLENDER_EEVEE'
 # ->.      use context here too instead of data. Just context, not bpy.context

this works:

import bpy

from bpy.types import (Panel,
                       Menu,
                       PropertyGroup,
                       )
                       
class MyProperties(bpy.types.PropertyGroup):

    my_enum0 : bpy.props.EnumProperty(
        name= "",
        description= "Change the render engine of the scene",
        items= [('OP1', "Cycles", "f"),
                ('OP2', "Eevee", "fg"),
        ],
        update=lambda self, context: bpy.ops.addonname.myop_operator00()
    )
    
class TestPanel(bpy.types.Panel):
    bl_label = "Quick Render Presets"
    bl_idname = "PT_TestPanel"  
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Example'
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        mytool = scene.my_tool  
    
        rowAA = layout.row()
        rowAA.label(text= "Render Engine:")
        
        layout.prop(mytool, "my_enum0")

class RenderRender2(bpy.types.Operator):
    bl_label = "Render Engine"
    bl_idname = "addonname.myop_operator00"
        
    def execute(self, context):
        scene = context.scene
        mytool = scene.my_tool
        
        if mytool.my_enum0 == 'OP1':
            context.scene.render.engine = 'CYCLES'
            print("tried cycles")
                      
        if mytool.my_enum0 == 'OP2':
            context.scene.render.engine = 'BLENDER_EEVEE'
            print("tried eevee")
        print("in execute")

            
        return {'FINISHED'}
    
classes = [MyProperties, RenderRender2, TestPanel]
 
 
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
        
    bpy.types.Scene.my_tool = bpy.props.PointerProperty(type= MyProperties)
        
 
def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.my_tool
 
    
if __name__ == "__main__":
    register()
$\endgroup$
4
  • $\begingroup$ Thank you for the entire code. $\endgroup$ Commented Apr 3, 2022 at 16:10
  • $\begingroup$ Of course, the OP doesn't need the property group, the row label, or the non-OO if statements in the execute function, or even wrapping a class around the update function. $\endgroup$ Commented Apr 3, 2022 at 16:29
  • $\begingroup$ @jugaadanimation : you are welcome $\endgroup$
    – Chris
    Commented Apr 3, 2022 at 16:32
  • 1
    $\begingroup$ @jugaadanimation be aware that the code was buggy until I fixed it just now. Never use bpy.context in any function that has context has a function argument. Use the context argument instead. $\endgroup$ Commented Apr 3, 2022 at 16:48
5
$\begingroup$

Actually, your design was overly complex. Here's a much simpler version

import bpy

from bpy.types import (Panel, Scene)

def updater(self, context):
    context.scene.render.engine = context.scene.my_enum0 
    
class TestPanel(bpy.types.Panel):
    bl_label = "Quick Render Presets"
    bl_idname = "PT_TestPanel"  
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'UI'
    bl_category = 'Example'
    
    def draw(self, context):
        layout = self.layout
        scene = context.scene
        layout.prop(scene, "my_enum0")
    
classes = [TestPanel]
 
 
def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    Scene.my_enum0 = bpy.props.EnumProperty(
            name= "",
            description= "Change the render engine of the scene",
            items= [('CYCLES', "Cycles", "f"),
                    ('BLENDER_EEVEE', "Eevee", "fg"),
            ],
            update=updater
        ) 

def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)
    del bpy.types.Scene.my_enum0
    
if __name__ == "__main__":
    register()

You don't need all of the extra overhead; or additional classes. The technique is that changing the enum in the panel can invoke an updater function and it's that function where you change render engines.

If you want tests or messaging, just put them in the update function. If you only want the one line version of the updater you can even remove the function and put it back as a lambda.

$\endgroup$

You must log in to answer this question.

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