3

Is it possible to simulate the Shift+LMB for hiding a parent object with its children as in the outliner. Now based on this and this I am iterating over the children objects and hide_set(True) them individually:

def toggle_hide (list, mode=True):
children_list = []    
for obj in list:
    if obj.children:
        children_list.append(obj.children)

    obj.hide_set(mode)

if children_list:
    for child in children_list:

        toggle_hide (child)

bpy.data.objects["parent"].hide_set(True) toggle_hide(bpy.data.objects["parent"].children)

bpy.data.objects["parent"].hide_set(True) hides only the parent object leaving the children unhidden, which I need to do it afterwards recursively.

My guess is that under the hood might be the same procedure that is happening but I was wondering if someone can just call the corresponding outliner build in function instead of re-implementing it or by passing some flag to the hide_set() though as I see it takes only a view_layer id.


Update (not working):

Now I want to add the solution from @batFINGER to a class, e.g.

import bpy
from bpy.props import BoolProperty

class Utility:

class AddHidingProperty:
    def __init__(self):
        bpy.types.Object.hide_children = BoolProperty(update=self.hide_children)

        bpy.types.TEXT_HT_footer.append(self.draw)

    def hide_children(self, obj, context):
        obj.hide_set(obj.hide_children)
        for o in obj.children:
            o.hide_children = obj.hide_children

    # function to draw the checkbox in the editor footer      
    def draw(self, obj, context):
        layout = obj.layout
        ob = context.object
        layout.prop(ob, "hide_children")

However when I call the Utility.AddHidingProperty(), this gives me the following error: ValueError: bpy_struct "Object" registration error: hide_children could not register.


Update 2 (working):

The following seems to work but I am not sure whether it is a good approach:

class Utility:
class AddHidingProperty:

    def __init__(self):

        def hide_children(obj, context):
            obj.hide_set(obj.hide_children)
            for o in obj.children:
                o.hide_children = obj.hide_children

        # function to draw the checkbox in the editor footer      
        def draw(obj, context):
            layout = obj.layout
            ob = context.object
            layout.prop(ob, "hide_children")

        bpy.types.Object.hide_children = BoolProperty(update=hide_children)

        bpy.types.TEXT_HT_footer.append(draw)

ttsesm
  • 409
  • 3
  • 10

1 Answers1

6

Define and toggle a boolean property

From the other answer to link https://blender.stackexchange.com/a/147144/15543 it gives the object a hide_children property that if set hides the object and sets hide_children hence setting recursively for all children.

A checkbox to set the property is added to the text editor footer for testing.

import bpy
from bpy.props import BoolProperty

def hide_children(self, context): self.hide_set(self.hide_children) for o in self.children: o.hide_children = self.hide_children

bpy.types.Object.hide_children = BoolProperty(update=hide_children)

def draw(self, context): layout = self.layout ob = context.object layout.prop(ob, "hide_children")

bpy.types.TEXT_HT_footer.append(draw)

Since the object can be found from context, can toggle the boolean value of the property using the window managers context toggle operator

After you have run the script above to register the property on the Object class

>>> C.object.hide_children
False

>>> C.object.hide_children = True

>>> bpy.ops.wm.context_toggle( context_toggle() bpy.ops.wm.context_toggle(data_path="", module="") Toggle a context value >>> bpy.ops.wm.context_toggle(data_path="object.hide_children") {'FINISHED'}

If You do not run the script beforehand will get an error

# same as not running script (unregister the property)
>>> del bpy.types.Object.hide_children 
>>> bpy.ops.wm.context_toggle(data_path="object.hide_children")
context_path_validate error: context.object.hide_children not found (invalid keymap entry?)
{'PASS_THROUGH'}

Assign a shortcut.

With the script above run, and the property defined can be set as a shortcut from context.

enter image description here Image of Edit > User Preferences > Keymaps

Since once hidden an object cannot have context, and from the 3d view there is no way to select as a group AltH will unhide all previously hidden objects.

Note both the object (self) and context is passed to the update method could instead hide all objects and their children looping over context.selected_objects

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • I am sorry but I do not understand that much of what you are doing there :-(. Could you explain a bit more. I was checking on your answer on the other thread as well but I couldn't figure out how to pass a specific parent object as input to hide_children(). You create this boolean property but how do I call/toggle it for a parent object. Also does the object needs to be selected first each time or I can call it by the name? If you don't mind I would appreciate if you could please provide a calling example. Btw I've run the script but I cannot see any window manager context toggle operator... – ttsesm Oct 08 '20 at 14:37
  • ...if I run bpy.ops.wm.context_toggle(data_path="object.hide_children") I am getting {'PASS_THROUGH'} instead of {'FINISHED'} as in your case. – ttsesm Oct 08 '20 at 14:37
  • See edit. Run the script first. The method fires when the property of an object is updated. The object is the owner of the property self in the update method. Blender's context operator paradigm rarely passes an object to a method, instead operates on context – batFINGER Oct 08 '20 at 14:53
  • Appreciated thanks a lot, I got it now. – ttsesm Oct 08 '20 at 15:30
  • one more question I want to add the code snippet above within an existing class as a subclass, however I am getting an error ValueError: bpy_struct "Object" registration error: hide_children could not register. Check on my update section, in the initial post. – ttsesm Oct 12 '20 at 13:46
  • The update method is going to be incorrect. It is expecting a method with 2 arguments, whereas self.hide_children(context) in this case has one, with self being an instance of your class. One way would be to define def hide_children(self, ob, context) making the distinction that when used as an update property the ob is the object. – batFINGER Oct 12 '20 at 13:54
  • But then I would need to pass each object ob individually or not? I do not get it. – ttsesm Oct 12 '20 at 14:10
  • AddHidingProperty.hide_children is a method definition that has two arguments, whereas in the init method self.hide_children is a method with one, eg if you were to call it it would be self.hide_method(context) because it belongs to the class instance the self is implied by the owner. Because self.hide_render only has one argument it fails to register. Use either update=hide_render or update=AddHidingClass.hide_render. This is basic python class method stuff. If you use with ob as suggested, then self is your class, and ob will be treated as the object with the property – batFINGER Oct 12 '20 at 14:21
  • being updated. The method assigned to an update function is required to have 2 arguments, which it would since you would call it from __init__ (for example) using self.hide_render(ob, context) ie a method that takes two arguments. If you don't need to discern between your class instance and the object instance, don't do it this way.\ You are going to have issues with draw next for same reasons.... – batFINGER Oct 12 '20 at 14:28
  • Ok, I was really confusing the self class instance with self object with the property. I've updated the code with the suggested def hide_children(self, ob, context) approach. I still get the error though. – ttsesm Oct 12 '20 at 15:57
  • 1
    Yep, bum steer, lol... should have checked. Notice the error TypeError: update keyword: expected a function type, not a method In python a function defined on a class is a method. Hence the registration error. Printing self.hide_children ...> <bound method Utility.AddHidingProperty.hide_children of <__main__.Utility.AddHidingProperty object at 0x7f658bb72fa0>> This makes sense since could del that class instance but the object would still be looking for an update method. Your last edit is using the function def, and hence is Ok. – batFINGER Oct 12 '20 at 16:39
  • I'll keep the solution in update 2 for now. It seems to do the job, though I am not sure whether it is the proper approach. Thanks a lot. – ttsesm Oct 12 '20 at 17:53