Hi, I want to write an addon that operates on multiple selected objects. However, it is important for me to know the order in which the objects (more than 2) are selected. However
bpy.context.selected_objects
always returns the objects in the same order. Is there any way to get the order in which the objects have been selected?
I have been monitoring this thread quite closely since this seems to be a simple task but I could not find a simple solution by searching though the documentation. All I found was this ‘bug report’:
So, I started thinking about others ways to retrieve the selection order.
Here is the basic idea/theory:
save the current active object
go back in time by using undo()
save the active object at that point in time
go back in time by using undo() and save the active object… until there is only one selected object left
use redo() several times in order to get back to the initial state
After that you will have saved a list of objects and their selection order.
I have put together a small proof of concept script. (I just started to check out python/blender scripting a few days ago - so don’t get confused if things look a little funny
import bpy
class PrintSelectionOrder(bpy.types.Operator):
bl_idname = "object.print_selection_order"
bl_label = "Print Selection Order"
def execute(self, context):
count = 0
# start list with current active object:
order = list([bpy.context.active_object.name])
#keep going back in time (undo) as long as objects are selected
while len(bpy.context.selected_objects) >= 2:
bpy.ops.ed.undo()
order.insert(0,bpy.context.active_object.name) # add previous active object
count += 1
self.report({'INFO'}, ', '.join(order)) # Output Order
# Get back to the future (redo, redo, redo, ...)
for x in range(0, count):
bpy.ops.ed.redo()
return {'FINISHED'}
def register():
bpy.utils.register_class(PrintSelectionOrder)
if __name__ == "__main__":
register()
Of course, there are still a lot of things which need to be considered in order to make this usable. (e.g. objects which get selected, de-selected and re-selected, damages which may be caused by using undo()/redo() this way, …) And it is quite clear that this will only work if the objects have been selected one after the other - things like rectangle select will most definitely break this. But maybe it is a start - and depending on the circumstances/intended use: probably better than nothing
thx RickyBlender and Helge. I will check both possibilities out. Helges idea is a great hack, very good idea. But of course, it would be better to retrieve this information in a more reliable way. But anyway, as a first implementation this would work already.
@liero: thx for the hint. I contacted already the developer of curve-tools
so I think there are some possibilities. Let’s hope that it will become soon a feature in one of the next releases of Blender. I put this already up on the developers mailing list
hey, thanks for the hint. that is really a hidden feature. after
import selection_utils
at the console it works and I can access the information with
selection_utils.selected
would be better to have the selection order by default available and not by switching to this special selection mode. But as a first start this helps already.
I second that comment, I am actively looking for this especially in 2.80
There’s some workaround but that makes it less user friendly tough.
Also there’s bpy.ops.object.select_order() but not sure how to best use it. Might update my post if I find something
I had this Problem too. Therefore I write a very easy shortcut, which when I press him, he write me the selected objects in a .txt file.
That means first select object, then press shortcut (k), then select next, press k and so on.
After that I call a little function which I called order_selection() and he write me the selection order in the python console
bl_info = {
"name": "Work Macro",
"category": "Object",
}
import bpy
class WorkMacro(bpy.types.Operator):
"""Work Macro"""
bl_idname = "object.work_macro"
bl_label = "Work Macro"
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
path=""
fileHandle = open (path + 'Order.txt', 'a' )
fileHandle.write (bpy.context.scene.objects.active.name)
fileHandle.write ('\n')
fileHandle.close()
return {'FINISHED'}
# store keymaps here to access after registration
addon_keymaps = []
def register():
bpy.utils.register_class(WorkMacro)
# handle the keymap
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='Object Mode', space_type='EMPTY')
kmi = km.keymap_items.new(WorkMacro.bl_idname, 'K', 'PRESS', ctrl=False, shift=False)
addon_keymaps.append(km)
def unregister():
bpy.utils.unregister_class(WorkMacro)
# handle the keymap
wm = bpy.context.window_manager
for km in addon_keymaps:
wm.keyconfigs.addon.keymaps.remove(km)
# clear the list
del addon_keymaps[:]
if __name__ == "__main__":
register()
import os
def order_selection():
path=""
fileHandle = open(path + 'Order.txt')
Aname=[]
for line in fileHandle:
Aname.append(line.rstrip())
fileHandle.close()
os.remove(path + 'Order.txt')
A=[]
for i in range(0, len(Aname)):
A.append(bpy.data.objects[Aname[i]])
print(A)
If there are two selection items, you can get the selection order.
in selected_objects of two, the active_object and the equal one is the second selected item.
Hi. Sorry I am writing in this old thread. IS there any solution for blender 2.8?
I have to rename a lot of objects and I need to have the selection order. The trick with undos works, but is extremely slow. Is there any faster solutions?