1
$\begingroup$

I am running Blender 3.0 on Ubuntu 21.10 with Python, trying to select an object I have just added but it keeps selecting the Cylinder instead of the Cube. Is that due to the order in which they are drawn?

Why does this script not select the Cube.

import bpy
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1))
bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
obj = bpy.context.scene.objects["Cube"]
obj.location.z +=1

enter image description here

Here is updated code which as you suggested deselects everything and select activates the object I want.

import bpy
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1))
bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
bpy.data.objects['Cylinder'].select_set(False); 
obj.select_set(True); 
bpy.context.view_layer.objects.active = obj

However now is doesn't seem to be highlight the cube. Thanks

enter image description here

By changing False to True only Cylinder is highlighted as expected.

enter image description here When I change Cylinder to Cube the cube is highlighted as expected. And so I should be able to use the boolean modifier or any modifier. Thanks for your help.

enter image description here

Strange it is selecting both objects now. Why is this? enter image description here

$\endgroup$
6
  • 3
    $\begingroup$ Does this answer your question? Selecting an object via scripting? You don't select an object, you add two objects (the last added is selected and active), and then assign it to variable to modify it. In order to select, you need to deselect the previous object, select the new one and make it active: bpy.data.objects['Cylinder'].select_set(False); obj.select_set(True); bpy.context.view_layer.objects.active = obj $\endgroup$ Commented Jan 11, 2022 at 18:52
  • $\begingroup$ Thanks for the link and for looking at this. I've seen that link before, thanks for it. I have updated the question to include your suggestions. $\endgroup$
    – ofey
    Commented Jan 11, 2022 at 19:18
  • 1
    $\begingroup$ The code I suggested was to be added to your original code, in which you define obj variable pointing to the object to be selected. In your updated code you no longer define obj, and so using the undefined name causes an error NameError: name 'obj' is not defined, stopping the execution of the script. Copy-paste my code and add it to your original code, then it should work. $\endgroup$ Commented Jan 11, 2022 at 19:55
  • $\begingroup$ will do thanks and i'll let you know how it goes. $\endgroup$
    – ofey
    Commented Jan 11, 2022 at 21:19
  • $\begingroup$ Ok Im' a bit confused now, So I added your code to the end of my original code and get import bpy bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1)) bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) bpy.data.objects['Cylinder'].select_set(False); obj.select_set(True); bpy.context.view_layer.objects.active = obj bpy.data.objects['Cylinder'].select_set(False); obj.select_set(True); bpy.context.view_layer.objects.active = obj But this selects nothing. $\endgroup$
    – ofey
    Commented Jan 11, 2022 at 21:32

3 Answers 3

5
$\begingroup$

The last added object with a primitive_add operator will be selected. Invert your two operator calls and you can have access to the cube :

import bpy

bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1))
cylinder = bpy.context.active_object
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1))
cube = bpy.context.active_object
bpy.context.active_object.location.z += 1 # same as cube.location.z += 1

print(cylinder)
print(cube)

<bpy_struct, Object("Cylinder") at 0x00000206999BE408>

<bpy_struct, Object("Cube") at 0x000002069A0A0108>

Edit : To select one or the other :

def select_one_object(obj):
    bpy.ops.object.select_all(action='DESELECT')
    bpy.context.view_layer.objects.active = obj
    obj.select_set(True)

select_one_object(cylinder)  # This will select the cylinder and set it as active
select_one_object(cube)  # This will select the cube and set it as active
bpy.context.view_layer.objects.active = None # After that you won't have an active object in the scene. Note it doesn't deselect the active object though.

Note there can be zero, one or more selected objects (yellow outline or orange outline), but there can only be zero or one active object (yellow outline). The active object can be unselected but still remain active. eg. when you click in the 3D viewport on an empty space, objects are unselected but the active object still has a yellow dot.

$\endgroup$
3
  • $\begingroup$ So what if you created three objects and then wanted to select the second object. $\endgroup$
    – ofey
    Commented Jan 12, 2022 at 15:47
  • $\begingroup$ I can just LMB on a shape normally without code. Is there an equivalent of this in code? $\endgroup$
    – ofey
    Commented Jan 12, 2022 at 16:02
  • $\begingroup$ Well just after yo ucreated an object bpy.context.active_object points to this object, so in this example cylinder and cube directly point to their respective objects. I've added some parts to my answer. But you do need a link to this object. You can however get a pointer to any object if you know its name with bpy.data.objects.get("object_name") $\endgroup$
    – Gorgious
    Commented Jan 12, 2022 at 21:54
3
$\begingroup$

This code does what you want:

import bpy 
 
 
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1)) 
bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) 
obj = bpy.context.scene.objects["Cube"]
bpy.data.objects['Cylinder'].select_set(False)
obj.select_set(True)
bpy.context.view_layer.objects.active = obj 

NOTE: But...you have to delete the two objects (if they exist) with the names "Cylinder" and "Cube" before starting that script because it hard coded the name "Cube" and "Cylinder" which is...pretty bad coding.

$\endgroup$
2
$\begingroup$

If you create an object with bpy.ops, it will become "active" after creation.

If you register the object in a variable when it is active, the next time you want to access the object, you can directly access the variable (data block) to manipulate the object and make it active again.

If you want to use "bpy.ops・・・・", you will need to make the object active once.

import bpy  

# If you create an object with bpy.ops, it will become "active" after creation.
 
bpy.ops.mesh.primitive_cube_add(enter_editmode=False, align='WORLD', location=(0, 0, 1), scale=(1, 1, 1)) 
# "bpy.context.object" stores the object in the active state in a variable.
add_obj1 = bpy.context.object

# Similarly, "bpy.context.object" stores the object in the active state in a variable.
bpy.ops.mesh.primitive_cylinder_add(enter_editmode=False, align='WORLD', location=(0, 0, 0), scale=(1, 1, 1)) 
add_obj2 = bpy.context.object


# If you want to change the location of the Cube.
add_obj1.location = (5.0, 5.0, 5.0)

# If you want to change the location of the cylinder.
add_obj2.location = (-5.0, 5.0, 5.0)

How to select it after the script

Sometimes you will want to select a specific object again after the script. In this case, you can select the object from the name of the object in the scene. In this case, you can select the object by its name, or you can use the RNA and ID properties to identify it.

Here's a point. If you select an object later by name If you change the name while you are working on it, you will not know how to set the object again. This is quite common.

With "Custom Properties", you can set the object in a way that does not depend on its name, With custom properties, the setting method is independent of the name. You may want to keep this method in mind if you want to select a particular object again later. You may want to keep this in mind.

enter image description here

Example

  1. 1 is selected
  2. 2 is selected and active state
  3. 0 is unselected
  4. And so on...

I have written four scripts.

Unselected script

bool_False.py

import bpy
    
def bool_False():
        bpy.types.Object.my_rna_bool = bpy.props.IntProperty(name='RNA bool')
        bpy.context.active_object.my_rna_bool = False
        layer = bpy.context.view_layer
        layer.update()
    
bool_False()

The script to make it selected.

bool_true.py

import bpy

def bool_true():
    bpy.types.Object.my_rna_bool = bpy.props.IntProperty(name='RNA bool')
    bpy.context.active_object.my_rna_bool = True
    layer = bpy.context.view_layer
    layer.update()
    
bool_true()

Script to select and make active

bool_active_true.py

import bpy

def bool_active_true():
    bpy.types.Object.my_rna_bool = bpy.props.IntProperty(name='RNA bool')
    bpy.context.active_object.my_rna_bool = 2
    layer = bpy.context.view_layer
    layer.update()
    
bool_active_true()

Script to output the result of the above configuration

select_set_active.py

import bpy


def select_set_active():
    for obj in bpy.context.scene.objects:
        print(obj.name, obj.get("my_rna_bool"))
        obj_bool = obj.get("my_rna_bool")
        if obj_bool == 2:
            # If there is more than one 2 in the value of the Int, the last one in the array will be active.
            bpy.context.view_layer.objects.active = obj 
            obj.select_set(True)
            
        elif obj_bool == 1:
            # select only.
            obj.select_set(True)
            
        else:
            
            obj.select_set(False)
            pass 

select_set_active()

enter image description here

Script results

enter image description here

$\endgroup$

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