6
$\begingroup$

I want to trigger a function when any mesh vertex is selected. After alot of research, using msgbus.subscribe_rna seems to be the way to go, unfortunately even though i can use it to trigger a function when say, objects are selected, when i try the same for changes in vertex propterties it has no effect.

import bpy


handle = object()

#subscribe_to = bpy.types.MeshVertex, "select" # Doesn't do anything
subscribe_to = bpy.context.object.data.vertices[0].path_resolve("select", False) #Doesn't do anything
#subscribe_to = bpy.types.LayerObjects, "active" # Triggers when an object is made active
#subscribe_to = bpy.types.Object, "location" # Triggers when an objects location is changed in N panel


def notify_test(*args):
    print("Notify changed!", args)

bpy.msgbus.subscribe_rna(
    key=subscribe_to,
    owner=handle,
    args=(),
    notify=notify_test,
)

bpy.msgbus.publish_rna(key=subscribe_to)
$\endgroup$
5
  • $\begingroup$ Interesting. Perhaps at issue here is akin to selecting vertices of Mesh.vertices has to be done in object mode. Running code above with MeshVertex.select triggers the message by running >>> C.object.data.vertices[0].select = False in console in object mode. $\endgroup$
    – batFINGER
    Commented Dec 14, 2019 at 14:48
  • $\begingroup$ Hmm that is interesting, presumably manually clicking the vertex to select it changes the .select attribute the same way as doing it through python so I can't imagine what the problem might be. $\endgroup$
    – Thiedent
    Commented Dec 14, 2019 at 14:59
  • $\begingroup$ The only other method i found was to generate an event for mouseClicks, which was extremely clunky and even so i would have to cycle through modes just to access any properties of the vertex. $\endgroup$
    – Thiedent
    Commented Dec 14, 2019 at 15:01
  • $\begingroup$ There is some "voodoo" seems like an instance is created to edit, then written back when mode toggled. Have done something similar by looking at edit bmesh select history active in a draw callback. see links in recent comment blender.stackexchange.com/questions/160877/… Make a dictionary of edit bmeshes from all meshes of objects in edit mode by mesh name, clear it if object mode changes. Works quite well. $\endgroup$
    – batFINGER
    Commented Dec 14, 2019 at 15:06
  • $\begingroup$ Hmm i'm not too familiar with that, but i'll look into it and see if i can make it work. Thanks $\endgroup$
    – Thiedent
    Commented Dec 14, 2019 at 15:18

1 Answer 1

6
$\begingroup$

An alternative using bmesh and a draw callback

enter image description here

As mentioned in comments, here is an alternative using a draw callback on the 3d view.

Simply prints the active element.

import bpy
import blf
import bmesh

bmeshes = {}
#from gi.repository import Gdk
class DrawingClass:
    def __init__(self, context, prop):
        self.prop = prop
        self.handle = bpy.types.SpaceView3D.draw_handler_add(
                   self.draw_text_callback,(context,),
                   'WINDOW', 'POST_PIXEL')

    def draw_text_callback(self, context):
        font_id = 0  # XXX, need to find out how best to get this.
        # draw some text
        blf.position(font_id, 15, 50, 20)
        blf.size(font_id, 20, 72)

        ob = context.object
        meshes = set(o.data for o in context.selected_objects if o.mode == 'EDIT')
        if context.mode == 'EDIT_MESH':
            for m in meshes:
                bmeshes.setdefault(m.name, bmesh.from_edit_mesh(m))
        else:
            bmeshes.clear()
            return
        me = ob.data
        blf.draw(font_id, f"{bmeshes[me.name].select_history.active}")

    def remove_handle(self):
         bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')

if __name__ == "__main__":
    # test call            
    dc = DrawingClass(bpy.context, "Auto Layer Running......")
    dns = bpy.app.driver_namespace
    dns["dc"] = dc
$\endgroup$

You must log in to answer this question.

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