0
$\begingroup$

How can I create a panel that allows me to add custom properties (StringProperty, BoolProperty, etc) for Collections? I want to show a GUI in the object properties when the user clicks a collection in the outliner. To create a panel you normally inherit from bpy.types.Panel and implement the draw(). The poll() function can be used to determine if the panel should be shown or not. The obvious approach is to use this feature. But how would this poll() look like? How do you know if a collection has been clicked by the user as shown in the screenshot below.

selected collection in outliner

When "my-collection" is clicked/selected I want to show a panel in the object properties. But how do I know if a collection has been clicked?

Update 1

enter image description here

I'll try to clarify the issue a bit more. In the image above I've made the "Sub" collection active. When I print the name C.collection.name you see that it prints "Sub". Now, let me make "Cube" active:

enter image description here

Now, when I print C.collection.name it prints "Sub" again; and although that's correct, that's not the info I'm trying to retrieve. I need to query some other context value which would give me the collection when "Sub" is active and "Cube" when the object is active.

$\endgroup$
1
$\begingroup$

It’s easier than you might think: Either get the collection in context (C.collection) or the collection of the active View Layer (C.view_layer.active_layer_collection). Both attributes return a reference to the selected collection in the Outliner allowing to access the name of the collection by using its name attribute to compare against.

Adding the following poll method to your panel class will only return True in case the selected collection is called MyCollection and thus display the panel:

@classmethod
def poll(cls, context):
    return context.collection.name == "MyCollection"

enter image description here

Code based on ui_panel_simple.py template:

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"

    @classmethod
    def poll(cls, context):
        return context.collection.name == "MyCollection"

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

        obj = context.object

        row = layout.row()
        row.label(text="Hello world!", icon='WORLD_DATA')

        row = layout.row()
        row.label(text="Active object is: " + obj.name)
        row = layout.row()
        row.prop(obj, "name")

        row = layout.row()
        row.operator("mesh.primitive_cube_add")


def register():
    bpy.utils.register_class(HelloWorldPanel)


def unregister():
    bpy.utils.unregister_class(HelloWorldPanel)


if __name__ == "__main__":
    register()

Further reading:

$\endgroup$
5
  • $\begingroup$ Thanks brockmann! There are a couple of things that don't work with this approach. 1. I actually don't want to specifically check for "My Collection"; I want any collection to work; but I think you just added the check for return context.collection.name == "MyCollection" as an example. 2. The active_layer_collection also has a value when I select an object in in the collection itself. I want to know when the collection is selected/active in the outliner; like if it has the blue background (not sure how to describe this better). Then I can toggle a gui for the object or for the collection. $\endgroup$
    – roxlu
    Aug 17 '20 at 7:43
  • 1
    $\begingroup$ As mentioned, you can get the "selected/active/blue" collection using C.collection, it's a reference so you've got access to all properties of that collection. In case you want to display properties per collections or per object in context, you don't need any poll method, would basically always be true -> Just add a condition to your draw method whether an object or collection is selected or just for both, done. @roxlu Does that help? $\endgroup$
    – brockmann
    Aug 17 '20 at 9:48
  • $\begingroup$ Thanks @brockmann! I've tried to clarify the question a bit more, see UPDATE 1 above. Maybe I need something like "outliner.active_node" (which I haven't found). And yes, what you suggest can work too but that's not exactly what I was trying to solve; but thanks for the suggestion; it might be the only thing that's currently possible. $\endgroup$
    – roxlu
    Aug 17 '20 at 11:25
  • 1
    $\begingroup$ So you'd like to get the active element in the Outliner? There is nothing like that... and honestly it doesn't matter in this case, you can have a panel for each element (object and collection) and can have one panel displaying the properties if one of them is active, even a sub-panel for the object in your main panel @roxlu $\endgroup$
    – brockmann
    Aug 17 '20 at 11:30
  • $\begingroup$ Ok thanks @brockmann if there is currently no way to get the active element in the Outliner then this is the best solution, thanks so much for your suggestions! $\endgroup$
    – roxlu
    Aug 17 '20 at 11:39

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.