I have a class that extends bpy.types.Panel. When a combination of items are chosen in another panel, I want this panel to appear, but not otherwise. Right now the panel will always show after being registered. I browsed through the documentation and found nothing useful. What function can I call or flag can I set to show and hide a panel, say, on clicking a button?
Poll the panel
Given this from the question
When a combination of items are chosen in another panel, I want this panel to appear, but not otherwise. Right now the panel will always show after being registered. I browsed through the documentation and found nothing useful. What function can I call or flag can I set to show and hide a panel,
to not show a panel at all have it not poll.
Every panel class has a
poll class method. Being a class method it is available without an instance of the class being created.
poll method return value is non
None or boolean
True then the panel shows. In the example below panel shows if the context scene name starts with "Scene"
If the panel polls it instances the panel and in doing so calls the draw methods (
draw if expanded)
draw method below draws the scene name property iff it is exactly "Scene" Remember it must poll. Only modifiying the poll will show name prop if the scene name is "Bob" for example.
A conditional in the draw method wont stop the panel from being drawn, just the content within. The poll method is the way to stop the panel from being drawn at all.
Have added an
__init__ method that prints "init", the poll method prints "poll" and the draw method "draw"
import bpy 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 __init__(self): print("init") @classmethod def poll(self, context): print("poll") scene = context.scene return scene.name.startswith("Scene") def draw(self, context): print("draw") layout = self.layout scene = context.scene if scene.name == "Scene": # it's the scene named "Scene" woohoo col = layout.column() col.prop(scene, "name") def register(): bpy.utils.register_class(HelloWorldPanel) def unregister(): bpy.utils.unregister_class(HelloWorldPanel) if __name__ == "__main__": register()
Have produced this answer because the idea that the draw method is called often is in fact not strictly the case, it is called only once per instance of the panel. The panel is instanced a lot... if it polls.
Running above when a scene name polls will print to console
poll # check if panel polls init # it polls init the panel draw # draw the content .... poll init draw poll init draw
or if it doesn't poll
poll poll poll ...
indicating that if the there is activity to redraw the area the panel resides, it checks if it polls, if it does it instances the panel and draws.
Can see here that rather than having conditionals in the draw, could set a particular
self.draw = self.draw_bob method when initializing the class.
Use a combination of both.
Given the OP's accepted answer, will speculate the panel resides in the file browser and is designed to show when a certain operator is being run. Changing code above such that panel resides in filebrowser tool props
bl_idname = "OBJECT_PT_hello" bl_space_type = 'FILE_BROWSER' bl_region_type = 'TOOL_PROPS'
to poll only when export scene obj (for example) is being run.
>>> bpy.ops.export_scene.obj.idname() 'EXPORT_SCENE_OT_obj'
a new poll method to reflect this
@classmethod def poll(cls, context): op = context.active_operator return op and op.bl_idname == "EXPORT_SCENE_OT_obj"
Will ensure the panel only instances when that particular operator is active.
Using this poll can rest assured in the draw code of the panel
context.active_operator both exists and is the one of interest.
Use conditionals in draw code based on the operators props, or what is more often the case these days use subpanels that poll based on a condition, within the condition of their parent panel.
Will notice more and more import export operators are beginning to use this method.
Why? to simply have an always polling panel (the default) and something like
op = context.active_operator if op.prop: pass
in draw code will throw an error constantly chattering messages into console like an endless stream of garbage when the operator doesn't exist or doesn't have a property
prop whenever the tool props panel of filebrowser is active for some other operator we are not interested in.