3

I need to know the current active vertex from within a Handler, so i do this:

import bpy, bmesh
from bpy.app.handlers import persistent

def find_active_vertex(bm):
    elem = next(reversed(bm.select_history), None)
    if isinstance(elem, bmesh.types.BMVert):
        return elem
    return None

@persistent
def edit_object_change_handler(scene):

    context = bpy.context
    obj=context.edit_object
    if obj and obj.type=="MESH" and context.mode=="EDIT_MESH":
        bm = bmesh.from_edit_mesh(obj.data)
        avi = find_active_vertex(bm)
        if avi:
            # ... more done here ...
            pass

def register():
    bpy.app.handlers.scene_update_post.append(edit_object_change_handler)

However this approach does not work. The following line seems to create a very unwanted misbehavior of Blender:

elem = next(reversed(bm.select_history), None)

As soon as i add this statement the weight editor in the "n" panel of the 3D View no longer accepts weight values as input.

So my question is: Is there an alternative to find the active Vertex within a Handler that does not affect the behavior of the Vertex Weights panel within the "n" properties sidebar of the 3D View ?

Gaia Clary
  • 3,802
  • 2
  • 24
  • 39

2 Answers2

3

Try reusing the bmesh instance, here I've used a global dic. Also I've used history.active

import bpy, bmesh
from bpy.app.handlers import persistent

def find_active_vertex(bm):

    elem = bm.select_history.active
    if elem is not None and  isinstance(elem, bmesh.types.BMVert):
        print("BVert", elem, elem.index)
        return elem
    return None

dic = {}
@persistent
def edit_object_change_handler(scene):

    obj = scene.objects.active
    if obj is None:
        return None

    if obj.mode == 'EDIT' and obj.type == 'MESH':
        bm = dic.setdefault(obj.name, bmesh.from_edit_mesh(obj.data))
        find_active_vertex(bm)
        return None

    dic.clear()
    return None

def register():
    bpy.app.handlers.scene_update_post.append(edit_object_change_handler)

register()

scene_update handlers are called around 200 times per second, (Sample file here https://developer.blender.org/T46329 ) Using the data to load bmesh that many times probably affected the vertex weight panel. I'd consider using a modal timer operator instead.

batFINGER
  • 84,216
  • 10
  • 108
  • 233
0

Just use bm.select_history[-1]. Also account for the chance that this raises an IndexError when the list is empty, of course.

dr. Sybren
  • 7,139
  • 1
  • 23
  • 52