Element selected in outliner and I don't want it to be

Hi,

I am in blender 2_92…

I run a script that takes a reference object (ReferenceThickLine), and creates copies of it (LineZinner_m_n_o, where the last created is LineZinner_04_1_3, meaning that it is left selected after being created). I apply a material to each copy.

The last lines of the code are:

bpy.ops.object.select_all(action='DESELECT')

bpy.data.objects["ReferenceThickLine"].select_set(False)

bpy.data.objects["ReferenceThickLine"].select_set(True)

The idea being to deselect LineZinner_04_1_3 and select ReferenceThickLine and that one only.

As you can see on picture below, left side, the result is that somehow, LineZinner_04_1_3 is still “kinda” selected, at least its material is. The red arrows point to where the problem is.

Picture:
extra_selected_item_both

When I click on ReferenceThickLine with the mouse, then it ends up being the only one that is selected, see picture, right side.

The question is: what do I have to do in the script to obtain picture 2 as a result and not picture 1?

Thank you.

P.S.: I tried bpy.ops.outliner.item_activate(extend=False, deselect_all=True), and I get to know that the context is incorrect, which is above my pay grade, meaning that if somebody could explain that one to me too, I would be delighted…

Hmm, can’t claim to know much about this.
So, yeah, in the first screenshot you see the old “active_object” (“LineZinner_…”), even though it’s not actually “selected”.
Here’s a bit of code I wrote for custom duplicating function a while back if it helps.
Someone on this forum once advised me to avoid bpy.ops if possible, so I did it like this:

    ## deselect all (just in case?) then select and activate newObject
    for selected in bpy.context.selected_objects:
        selected.select_set(False)
    newObject.select_set(True)
    bpy.context.view_layer.objects.active = newObject
2 Likes

Its like @StrayBillie said. You just updated the selected objects, but not the active object. In blender there’s the concept of an active object. There “normally” always is an active object ( just a few exceptions exist) , it can’t be deselected, and its always just one (and in rare cases none). If you do clicks in the outliner with the mouse the last object clicked will be the active object. If you do it by code you have to take care about its state. Blenders concept is a bit confusing as in blender there exist selected objects, the active object and even selected/highlighted rows of the outliner and they all may be different.

Have a look here:
https://docs.blender.org/manual/en/latest/scene_layout/object/selecting.html

For 2.8 or later this will do what you want:

import bpy
bpy.ops.object.select_all(action='DESELECT')
obj = bpy.data.objects["ReferenceThickLine"] 
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
2 Likes

StrayBillie and Debuk: Thank you for the code, it solved the issue!

StrayBillie: can you elaborate on not using ops, because I do all the time, and being new at this, maybe I can learn something new and useful!

Wish I could tell something useful but I’m probably more of a noob at this =D Tbh, my dive into code was a year ago and lasted like 2-3 days, so take it for what it’s worth.

At the time, I tried to override ops “Duplicate” operator. It worked but with weird unexplained consequences: right selection, wrong parenting, strangely linked data. Got stuck.
At least in that particular case simple Duplicate wasn’t going to cut it anyway: needed control over children, linked data, selectability…
I suppose it depends on the case, but ditching ops altogether and using straight data might actually expand possibilities. Yes, it requires to explicitly write more things: link new copies to Collections, consider relative transforms, adjust target objects in Modifiers, and who know what else might come up… on the other hand, this level of control was just what my script needed. Also never had to worry about “incorrect context”. Got easier to expand functionality too.

There’s nothing really wrong about using bpy.ops. So if it does what you want you reached your goal. But if you teach yourself to do it just that way, you end up coding rather like programming/recording macros and thats not the only nor is it the intended way to use the API. There are more direct ways to communicate with blenders internals in the API, and following these will lead to more efficient code, and will rather guarantee to have no unintended sideeffects.( eg. undo step creations, datastructure updates, redraws or any sort of internal statechange) You will also learn much more how blender works if you are not just relying on ops. There could be said much more on its sideeffects and the execution context, but in the end it all comes down to what I said.

But as a starting point: https://docs.blender.org/api/current/bpy.ops.html

2 Likes

Thank you for the explanation.

Yes, in fact, I had not noticed that I got problems from using bpy.ops. So as you say, I might as well go on until I can figure out other ways.

That was until you mentioned a specific sideeffect I am in fact concerned about: do you mean to say that using bpy.ops instead of more arcane methods results in longer execution time for the script?

If that is the case, I’d better get my sh… together because my script creates quite a few objects and I can see that the more I create, the longer it gets, nearly exponentially, it seems, since as I read somewhere recently, after every object is created, blender redraws all objects up to the newest.

Can you give hints as to what I should use instead of “bpy.ops.mesh.duplicate_move” if it is one of the commands that will result in lengthier runs for the script?

I did look at the doc you mention, and it is kinda over my head as to how I can use it, especially concerning another topic I am asking for help here, namely being able to create loopcuts on a cube by script (I currently get the ominous “Operator bpy.ops.mesh.loopcut_slide.poll() expected a view3d region & editmesh” error message…)

Thank you.

I wouldn’t have called the normal API calls arcane. :grin: What I meant is that you can use for sure operator calls if you like but you have to be aware that its really never the optimal way. So if you don’t mind it not being ideal and if you experience that it runs fine for you, then why change it. It might be worth not thinking about it any further if in your usecase it has no drawbacks becoming apparent. But yes its really not advised, because they all really do things like etablishing undos what can easily lead to massive amounts of data being copied/backuped if you do it constantly. You might have also realized yourself that this obviously not true for every single command thinkable as operator.

Regarding your other question, its somehow hard to give any good advice what to use instead of duplicate_move without knowing what you really want to achieve.

Multiple Objects have per se an overhead over a single one, so if you are adding primitive objects it might be worth to add that into a single mesh. Instantiation/Resuing mesh data in multiple objects might be clever. If you dont know what that is you should first read about the concept of instantiation. Overall it really depends.

But as a more concrete hint on how you might do such things in blender, here is an example that creates new objects:

https://docs.blender.org/api/current/bpy.types.Object.html

Instead of light_data and that light centric stuff you might give them other names and so on and set the object_data to something you already have, so that they share it, like:

reuseableData = bpy.data.objects[“ReferenceThickLine”].data

You might then change the location as it is already done in the example. If you want some user interactivity on placement then you should write an operator that utilizes mouse_events. Just google that, if thats what you want.

I hope that helps.

Thanks so much for your patience.

I can see that I have a lot to learn!

I’ll have to reflect on all that.

I liked the mention of “instanciating”, if that is the right expression, the various objects in one mesh.

Wouldn’t it make it difficult to assign different materials to the many thin elongated cubes I would end up with within a single Mesh?

The example you sent me to relieved me: I can do a lot of that, and yet, there was some new interesting syntax there for me.

Thanks again!

If you want to place cubes and they all shall have different materials, eg different complex pbr setups, then managing that by hand in the end might be indeed cumbersome. If its about procedural application thats another story.

Library overrides may also be handy in case of many materials for identical meshes: https://docs.blender.org/manual/en/latest/files/linked_libraries/library_overrides.html

Glad I could help. Good luck.