0
$\begingroup$

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?

$\endgroup$
8
  • 2
    $\begingroup$ A simple if statement in draw() based on a certain state/flag/bool should do it. Suggest adding your code otherwise it's impossible to answer your q. Please read: blender.stackexchange.com/help/how-to-ask $\endgroup$ – brockmann Jun 14 '20 at 12:31
  • 2
    $\begingroup$ See also docs.blender.org/api/current/… $\endgroup$ – batFINGER Jun 14 '20 at 13:09
  • 1
    $\begingroup$ @brockmann Wouldn't poll() be better? blender.stackexchange.com/questions/82957/… $\endgroup$ – Ray Mairlot Jun 14 '20 at 14:29
  • 1
    $\begingroup$ Sure possible too. However, depends on the condition and whether the panel or its elements should appear/disappear (in conjunction with the other panel mentioned in the question). I don't know... the reason why I asked for the actual script @RayMairlot $\endgroup$ – brockmann Jun 14 '20 at 14:41
  • 1
    $\begingroup$ Put an __init__ with a print in your panel class and will see it is instanced at regular intervals. The poll classmethod determines whether to. $\endgroup$ – batFINGER Jun 15 '20 at 12:43
3
$\begingroup$

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.

if the 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_header, and draw if expanded)

The 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.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy