B3.2: outline show active

Hi all :slight_smile:

Outliner window is able to show active object with the ‘KEYPAD .’ key.

How is it achievabale in python please ? :slight_smile:

Happy blending !

I believe you are looking for:

bpy.ops.view3d.localview(frame_selected=True)

2 Likes

hi @nezumi.blend

Thanks for your answer. Am not sure what does

bpy.ops.view3d.localview(frame_selected=True)

as it raises an error in the python console:
Failed, context is incorrect.

The point is that i was not talking about the 3D view but about the outliner window…

well…
I found the

bpy.ops.outliner.show_active() that should seem to do what i want but it raises an error ( again, context is incorrect ) :confused:

EDIT: what i understand from the errors is that what i want to do cannot be done in the draw function of a panel… :confused:

EDIT2: what i need to do is to show the active object in the outliner window…
Sounds pretty simple to do bu appears to be hell to code^^
Anybody could help please ? :slight_smile:

These operators need to be called from within the context of a particular editor (the 3D viewport for bpy.ops.view3d.localview and the outliner for bpy.ops.outliner.show_active). It means you want to draw a button linking to this operator in the interface of one of these editors. If you call it from an alternative context (or via code), it will throw an incorrect context error. It is annoying, but it is what it is…

You can override the operator by passing it the correct context, though, but it means getting access to it by other means. If you use these keywords in a search engine you should find some examples.

However by design you shouldn’t call operators or modify any data in a draw method, this method is only supposed to be used to display data. It is called dozens of time per second, and every time the UI needs refreshing. Most of the data structures of blender objects are locked for edition when you are in the scope of this method.

Could you add a bit of information about your current script so we can try to see how your desired behaviour can fit in it ?

3 Likes

Hi @Gorgious and thanks for your answer.

I slowly understand things in python/blender and this makes sense that the draw function is not intended for doing anything but UI draw.

I then had a look at handlers and found that bpy.app.handlers.depsgraph_update_post would suit my needs.
I then set up a handler on depsgraph_update_post and tried to find some info on context switching.
In my handler func, i wrote this:

def oldshow_active():
    override = None
    for area in bpy.context.screen.areas:
        if 'OUTLINER' in area.type:
            for region in area.regions:
                if 'WINDOW' in region.type:
                    override = {'area': area, 'region': region}
                    break
            break
    if override is not None:
        bpy.ops.outliner.show_active(override)

This works pretty fine with a flag for preventing useless recursion but am told that this method is deprecated. Instead i should use Context.temp_override(…).

Then i tried to replace the func with:

def newshow_active():
    areaOverride=bpy.context.area  
    if bpy.context.area is not None:
        if bpy.context.area.type!='OUTLINER':
            #If needed find the outliner area
            for area in bpy.context.screen.areas:
                if area.type == 'OUTLINER':
                    areaOverride=area

    with bpy.context.temp_override(area=areaOverride):
        bpy.ops.outliner.show_active(areaOverride)

wich raises errors in the console. I probably don’t know how to use this temp_override function…

Could you please help ?

Thanks and happy blending !

well :confused:

I got no idea why this works, but it works:

def show_active():
    override = None

    for area in bpy.context.screen.areas:
        if area.type == 'OUTLINER':
            for region in area.regions:
                if 'WINDOW' in region.type:
                    override = {'area': area, 'region': region}
                    break
            break

    with bpy.context.temp_override(area=bpy.context.area):
        bpy.ops.outliner.show_active(override)

temp_override param is nonsense and as there’s no doc nor info on this i can tell nothing.
If anyone got consistent info on how this works i’d be pleased to read ! :slight_smile:

Happy blending !

So here’s the full piece of code:


alreadyHere = False

def show_active(scene):
    global alreadyHere

    if(bpy.context.object.mode == 'EDIT'):
        return

    if(alreadyHere==False):
        alreadyHere=True
        
        override = None

        for area in bpy.context.screen.areas:
            if area.type == 'OUTLINER':
                for region in area.regions:
                    if 'WINDOW' in region.type:
                        override = {'area': area, 'region': region}
                        break
                break

        with bpy.context.temp_override(area=bpy.context.area):
            bpy.ops.outliner.show_active(override)
            
            
    alreadyHere=False
#==========================================================================================    



def add_handler(handlers, func):
    c = 0
    r = False
    for i in handlers:
        if i.__name__ == func.__name__:
            handlers.remove(handlers[c])
            r = True
        c += 1
        
    handlers.append(func)
    
    print(("Added" if r == False else "Replaced")+" Handler:", i.__name__)
#==========================================================================================    


def register():
    add_handler(bpy.app.handlers.depsgraph_update_post, show_active)



f __name__ == "__main__":
    register()

The purpose is pretty simple: always center the outliner on the active object ( a feature blender SHOULD have IMHO )
Don’t ask me how and why it works, i got absolutely no idea :stuck_out_tongue:

Happy blending !

1 Like

Sounds useful, I’m going to have to try this out :slight_smile:

1 Like

be carefull @joseph !

my script fux-up the loop cut & slide function when in edit mode…

For this problem not to happen you have to check for edit mode in handler and return immediately when edit mode is on :slight_smile:


    if(bpy.context.object.mode == 'EDIT'):
        return

Happy blending !

1 Like

Hi there :smiley: back to this lil script that worked perfectly in B3.5 but don’t work anymore in B4.1…

Could anyone please tell me why ?
What changed in 4.1 that generates an error ?

Thanks for your help :slight_smile:

wooops got it :slight_smile:

It appears ( tho am not sure ) that i used things unproperly :wink:

this one:

alreadyHere = False # flag preventing recursion...
def ShowActive(scene):
    global alreadyHere

    if(bpy.context.object.mode == 'EDIT'):
        return

    if(alreadyHere==False):
        alreadyHere=True

                
        override = None

        for foundArea in bpy.context.screen.areas:
            if foundArea.type == 'OUTLINER':
                for reg in foundArea.regions:
                    if 'WINDOW' in reg.type:
                        override = {'area': foundArea, 'region': reg}
                        break
                break
        
        with bpy.context.temp_override(area=foundArea,region=reg):
            bpy.ops.outliner.show_active()
            
            
    alreadyHere=False

works fin in B4.1 :wink:

Happy blending !