I've added a checkbox to the custom Blender UI Panel with a function assigned to it which is being executed on every checkbox update. The idea of that function is to extend Blender Top Menu with the custom Operator's button when the checkbox is checked and remove this button from the Menu when it is unchecked.
The first part - extending menus with the custom operators - is described in the current API documentation, and it works fine like this:
def menu_draw(self, context):
self.layout.operator("my_render.operator")
bpy.types.TOPBAR_MT_render.append(menu_draw)
But I can't find a way to remove this button from the menu once it has been added. It seems that it should be something like:
bpy.types.TOPBAR_MT_render.remove(menu_draw)
and in the documentation of this remove method it is said that it should remove the drawing function from the menu - and somehow it even works: I mean it executes and raises no Errors - but nothing happens, the button remains in the menu.
Is it a bug of this .remove() method for Menu classes or am I doing something wrong and it is supposed to work in some other way?
Of course I could just write two different TOPBAR_MT_render Menu classes (the first one as a copy of the original one and another one as its new custom version), place them in two different modules and then unregister existing -> import proper one -> register imported every time the checkbox is changed, but as far as it is possible I would like to avoid it.
I'm using Blender 2.83.3.
Thanks for the help in advance!
UPD
Thanks everyone, I've found a mistake! Your comments have really helped to figure out where was the issue. I placed an activating function inside the Operator class and tried to append/remove it right from inside of it, so every time the Operator was called, another instance of this function was used - that's why the previous one could not be removed from the TOPBAR_MR_render. Now I moved the activating function ttr_draw() outside the operator class and everything works perfect. Here's the code I had before:
import bpy
from bpy.props import BoolProperty, FloatProperty, PointerProperty
from bpy.utils import register_class, unregister_class
class TTR_TopMenuExtend(bpy.types.Operator):
bl_idname = 'ttr.top'
bl_label = 'Extend Top Menu'
def execute(self, context):
def ttr_draw(self, context): # This function should be moved out of this class
layout = self.layout
layout.operator("ttr.operator", icon='RENDER_ANIMATION')
if context.scene.ttr and context.scene.ttr.activate:
bpy.types.TOPBAR_MT_render.append(ttr_draw)
else:
bpy.types.TOPBAR_MT_render.remove(ttr_draw)
return {'FINISHED'}
def ttr_activate(self, context):
'''Activating function'''
bpy.ops.ttr.top()
class TTR(bpy.types.PropertyGroup):
'''Properties Group for UI Panel'''
activate : BoolProperty(
name="",
description="Enable",
default=False,
update=ttr_activate
)
speed : FloatProperty(
name="Speed",
description="Speed",
default=100.0,
min=0,
soft_max=300.0,
subtype = "FACTOR"
)
class TTR_PT_panel(bpy.types.Panel):
'''Create UI Panel in the render properties window'''
bl_label = "My TTR Add-on"
bl_idname = "RENDER_PT_ttr"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_options = {'DEFAULT_CLOSED'}
bl_context = "render"
bl_category = 'My TTR Add-on'
def draw_header(self, context):
layout = self.layout
scene = context.scene
props = scene.ttr
col = layout.column()
col.prop(props, "activate")
def draw(self, context):
layout = self.layout
layout.use_property_split = True
scene = context.scene
props = scene.ttr
layout.active = props.activate
col = layout.column()
col.prop(props, "speed")
class TTR_Operator(bpy.types.Operator):
'''Custom Operator to be called from the Top Menu'''
bl_idname = "ttr.operator"
bl_label = "My Custom Operator"
def execute(self, context):
return {'FINISHED'}
classes = [
TTR_TopMenuExtend,
TTR,
TTR_Operator,
TTR_PT_panel
]
def ttr_register():
for cl in classes:
register_class(cl)
def ttr_unregister():
for cl in classes:
unregister_class(cl)
if name == 'main':
ttr_register()
bpy.types.Scene.ttr = PointerProperty(type=TTR)
menu_drawstill refers to the same function the API should be able to remove it. – Robert Gützkow Aug 07 '20 at 21:31