# Update StringProperty on object selection change?

I have a StringProperty that I want to show the name of the selected object. Currently, I update the property by invoking an operator manually from a panel. However, I want the property to be updated automatically every time the selected object in the viewport changes.

What is the best way to achieve this?

I have considered running a modal operator, which checks the selection change all the time. However, that does not seem like an optimal solution. I have also tried playing around with handlers (bpy.app.handlers.scene_update_post as mentioned here), but it seems to have the same result as a modal operator (constant checking in infinite loop). Is it possible to trigger the update only when the selection changes by some callback? Or alternatively, when the right mouse button is clicked (assuming selection only happens this way)?

Edit, for clarification:

I specifically need a StringProperty to be updated, and not just a regular text label. This is because the StringProperty (and other properties) will display some specific information about the selected object, which the user then can change to change the selected object.

My current code, where the StringProperty is updated manually by click:

import bpy

# Define string property.
class MyGroup(bpy.types.PropertyGroup):
bpy.types.Scene.my_string = bpy.props.StringProperty(name='my_string')

# Define operator to change string property.
last_selection = []
bl_idname = "update.mystring"
bl_label = ""
def invoke(self, context, event):
global last_selection
if bpy.context.selected_objects != last_selection:
last_selection = bpy.context.selected_objects
bpy.context.scene.my_string = bpy.context.selected_objects[0].name
return {'FINISHED'}

# Draw property and operator.
class MyPanel(bpy.types.Panel):
...
def draw(self, context):
layout = self.layout
layout.row().prop(context.scene, "my_string")
layout.row().operator("update.mystring", text="Update")

# Register.
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()

• reimplementing the selection tool may help if you include the update inside of it May 25, 2015 at 19:08
• @Chebhou That is definitely not a bad idea. Would it be possibe to add such a modification in an addon without having to change the settings? If that is the case, I will accept it with some sample code as an answer. May 25, 2015 at 23:41
• "I have a StringProperty that I want to show the name of the selected object" why not just display the name of the currently selected object in a panel? I'm curious why you need a custom string property to display an already existing and identical string property that is bpy.context.selected_objects[0].name? May 27, 2015 at 0:07
• @patmo141 I need a StringProperty to be updated. Not a text label. I need to be able to change the name and other properties of the object by changing the corresponding StringProperties, which should be updated on selecting the object. May 27, 2015 at 2:35

This is the full script for selection and update, where emped the update function in our custom selection tool, the last function replaces the shortcuts of the old select with this operator so no damage is done and when unregistering the addon the shortcuts are reset to the previous state. run the script and open the Tools panel ( T in viewport ) and select an objectto see the string update

import bpy
from bpy.props import BoolProperty, IntVectorProperty

class MyGroup(bpy.types.PropertyGroup):
bpy.types.Scene.my_string = bpy.props.StringProperty(name='my_string')

# Define operator to change string property.
last_selection = []

# the selection operator with the update func :
class SelectionOperator(bpy.types.Operator):
""" Costum selection
"""
bl_idname = "view3d.select_costum"
bl_label = "costum selection"

extend = BoolProperty(default = False)
deselect = BoolProperty(default = False)
toggle = BoolProperty(default = False)
center = BoolProperty(default = False)
enumerate = BoolProperty(default = False)
object = BoolProperty(default = False)
location = IntVectorProperty(default = (0,0),subtype ='XYZ', size = 2)

def execute(self, context):
#select the object
bpy.ops.view3d.select(extend=self.extend, deselect=self.deselect, toggle=self.toggle, center=self.center, enumerate=self.enumerate, object=self.object, location=(self.location[0] , self.location[1] ))
#change the property
global last_selection
if bpy.context.selected_objects != last_selection:
last_selection = bpy.context.selected_objects
bpy.context.scene.my_string = bpy.context.selected_objects[0].name

return {'FINISHED'}

def invoke(self, context, event):
if context.space_data.type == 'VIEW_3D':
self.location[0] = event.mouse_region_x
self.location[1]  = event.mouse_region_y
return self.execute(context)
else:
self.report({'WARNING'}, "Active space must be a View3d")
return {'CANCELLED'}

def replace_shortkey( old_op_name, new_op_name) :

wm = bpy.context.window_manager
keyconfig = wm.keyconfigs.active
keymap = keyconfig.keymaps['3D View']
items = keymap.keymap_items

item = items.get(old_op_name, None)
while item :

props = item.properties

extend    = props.extend.real
deselect  = props.deselect.real
toggle    = props.toggle.real
center    = props.center.real
enumerate = props.enumerate.real
object    = props.object.real

item.idname = new_op_name

props.extend    = extend
props.deselect  = deselect
props.toggle    = toggle
props.center    = center
props.enumerate = enumerate
props.object    = object

item = items.get( old_op_name, None)

# Draw property and operator.
class HelloWorldPanel(bpy.types.Panel):
"""    """
bl_label = "active object Panel"
bl_idname = "OBJECT_PT_my_panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'TOOLS'

def draw(self, context):
layout = self.layout
layout.row().prop(context.scene, "my_string")

# Register.
def register():
bpy.utils.register_module(__name__)
replace_shortkey( 'view3d.select', SelectionOperator.bl_idname )

def unregister():
replace_shortkey(SelectionOperator.bl_idname, 'view3d.select')
bpy.utils.unregister_module(__name__)

if __name__ == "__main__":
register()

• Thank you, this is exactly what I was looking for. Definitely the cleanest and most flexible solution. May 27, 2015 at 16:01
• @Banana you are welcome , glad I could help May 27, 2015 at 16:04
• @Banana I still don't understand why you need to go through all that, can you help me understand? Chebhou's code is effective, but I just don't see why you need all that for what your problem describes. May 27, 2015 at 16:39

Why not just access the selected object's name when you need it? Blender panels are updated when blender re-draws. This only happens with user interaction so blender will check the selected object at a rate that is appropriate and you never have to worry! That's what the whole "context" thing is for. Unless there is some other reason you need to monitor selection I think you might be over complicating things.

class MyPanel(bpy.types.Panel):
def draw(self, context):
layout = self.layout
row = layout.row()
if len(context.selected_objects):
ob = context.selected_objects[0]
row.prop(ob, "name")

• This does not answer my question. I don't think you read it properly. I need a StringProperty to be updated. Not a text label. I'm not sure I could be much more clear as I specified it both in the title of the question and bolded in the text. The reason: I need to be able to change the name and other properties of the object by changing the corresponding StringProperties, which should be updated on selecting the object. May 27, 2015 at 2:33
• Ok, I understand what you want, but I don't understand why you want it. Why do you need a separate string property to represent what is already a string property? I see that you want to be able to edit the properties of the selected object like in the object properties panel. I still am unclear why you need a separate duplcate property. Why not just edit the one you are trying to edit? May 27, 2015 at 15:14
• ok, answer edited so it's a property not a label May 27, 2015 at 15:24
• The only thing I can think of, is that you want to change Properties that are not Strings, based on some string input from the user. Eg, you parse/process that string, and then update some Float, Int or other property. Is that what you want? May 27, 2015 at 15:26