9
$\begingroup$

I am wondering if following statements are true:

  • active_object is always identical to object.
  • active_object(or object if previous statement is true) is always the first one of selected_objects. (This seems to be a false statement since if I use bpy.ops.object.select_all(action='DESELECT') the active_object and object is not changed while selected_objects is empty.)
$\endgroup$

3 Answers 3

8
$\begingroup$

I am fairly sure the first is true, but the second isn't.

The list of selected_objects is expanded as new objects are added, new selections are added to the end of the list, while manually selecting the last addition will be the active object, so active_object is rarely the first in the selected_objects list.

There are some conditions that may catch you out.

  • When deselecting all objects, the last active object remains active even though it may no longer be selected.
  • When setting items as selected with python the active object does not automatically change.
  • Select all does not alter the active object.
  • Deleting the active object leaves you with no active object.
$\endgroup$
2
  • $\begingroup$ Thank you very much for extra information on these three attributes. But I failed to find the source evidence of "while manually selecting the last addition will be the active object". Can you give me some directions? $\endgroup$ Mar 20, 2015 at 7:41
  • $\begingroup$ In the 3dview select an object and in the python console enter bpy.context.selected_objects, select another object and repeat in console. You will see that the newly selected object will have the lighter outline of the active object and be the last in the selected list. shift select an already select object and it will be active but the list doesn't change. I expect the source is in source/blender/editors/space_view3d/view3d_select.c $\endgroup$
    – sambler
    Mar 21, 2015 at 4:36
3
$\begingroup$

After I post this question I think I can have a look at the implementation(f51a3aedc9540e0bcda4f16deec22e9aa722ef24) for answer.

Firstly, active_object and object refer to the same object when you try to access either one of them.

The attribute retrieving happens in the function ed_screen_context(file screen_context.c). This function performs string matching on the attribute names. For active_object and object you can see both of their implementations return obact(It is scene->basact actually) as result.

Secondly, when you set an active object through scene.active = ..., active_object and object are assigned by that object.

The call chain of this process is SceneObjects_active_set(file rna_scene_gen.c) -> rna_Scene_active_object_set(file rna_scene.c). In the function rna_Scene_active_object_set you can see the active object is assigned to scene->basact.

Finally, selected_objects seems to be a totally different thing from active_object and object.

The selecting of an object happens in function Object_select_set(file rna_object_gen.c). But I failed to find the relation between active_object and selected_objects as @sambler said.


EDIT: The relation between selected_objects and active_object/object is confirmed.

as @sambler said

while manually selecting the last addition will be the active object, so active_object is rarely the first in the selected_objects list

A selecting triggered by manual action happen in a space operator, rather than in a Python script binding. So I search this operator in view3d space. I found the operator VIEW3D_OT_select in file view3d_select.c. And there is a call chain of view3d_select_exec -> mouse_select -> ED_base_object_activate. I see the object activation happens in ED_base_object_activate:

if ((oldbasact != basact) && (is_obedit == false)) { ED_base_object_activate(C, basact); /* adds notifier */ }

Therefore the last selection will be the new active object.

$\endgroup$
0
$\begingroup$

In Blender 3.0 (I didn't check earlier versions), context.active_object is NOT always the same as context.object.

A situation in which this is the case is if you run the code from a "PROPERTIES" panel. That happens for example if you run an operator by clicking a button in the properties panel.

Here are two functions to prove what I'm talking about. Simply copy-paste them into a console and run them.

def print_objs_1():
    C = bpy.context
    C.area.type ="PROPERTIES"
    bpy.ops.mesh.primitive_cube_add()
    print(C.object)                    # None or some other already existing object
    print(C.active_object)             # New cube
    print(C.view_layer.objects.active) # Same new cube
    C.area.type="CONSOLE"

def print_objs_2():
    C = bpy.context
    obj = C.scene.objects[0]
    C.view_layer.objects.active = None # setting no active object while still in console panel
    C.area.type ="PROPERTIES"
    C.view_layer.objects.active = obj
    print(C.object)                    # None or some other already existing object
    print(C.active_object)             # obj
    print(C.view_layer.objects.active) # also obj
    C.area.type="CONSOLE"

(C.view_layer.objects.active is the new version of C.scene.objects.active, as stated in this question: https://blender.stackexchange.com/a/124259)

This (limited) information suggests that you should either use active_object instead of object in your scripts as a general rule, or make sure the C.area.type isn't of type "PROPERTIES" in parts of your code where it counts.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .