Skip to main content
added 7 characters in body
Source Link
batFINGER
  • 85.1k
  • 10
  • 114
  • 244

To elaborate on @Hikariztw 's answer

Using the code from https://blender.stackexchange.com/a/141207/15543 as an example.

Update to the property group def.

class MaterialSlot(PropertyGroup):
    def get_name(self):
        return self.get("name", "Foo")

    def set_name(self, value):
        oldname = self.get("name", "Foo")   
        self["name"] = value
        print(oldname, value)
        
    material : PointerProperty(type=bpy.types.Material)
    name : StringProperty(
            default="Foo", 
            get=get_name, 
            set=set_name)

Note the example code uses the material name in list UI class. Change to show item in draw method to show collection item name instead.

layout.prop(item, "name", text= "", emboss=False, icon_value=layout.icon(ma))

Python console code, added a new scene material slot. It is given the default name "Foo". Updating the name to "Bar", in this case via console, same if done via UI, and the setter is called. Which prints old name "Foo" and new name "Bar"

>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> s.name = "Bar"
Foo Bar

and again from "Bar" to "Choo"

>>> s.name = "Choo"
Bar Choo

But here is the "rub" re the property default value. The PropertyGroup class already has a name attribute. When a new item is first added, it doesn't use the name property default of "Foo", but rather defaults to "".

>>> C.scene.material_slots.clear()
>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> C.scene.material_slots.keys()
['']

ie collection has a material_slots[""] member rather than material_slots["Foo"] However if we set it implicitly, it picks up as expected... which is usual practice I suppose.

>>> s.name = "Foo"
Foo Foo

>>> C.scene.material_slots.keys()
['Foo']

EDIT re comment

so when I update the list element's name I need to find all objects with the original element name and then change it to the new name

For example above, to set all items with old name to new name, do this on a custom property level too. Add something like below to set_name method above.

if oldname != value:
    same = [s for s in self.id_data.material_slots
            if oldname == s.get("name", "Foo")]
    for s in same:
        s["name"] = value

To elaborate on @Hikariztw 's answer

Using the code from https://blender.stackexchange.com/a/141207/15543 as an example.

Update the property group.

class MaterialSlot(PropertyGroup):
    def get_name(self):
        return self.get("name", "Foo")

    def set_name(self, value):
        oldname = self.get("name", "Foo")   
        self["name"] = value
        print(oldname, value)
        
    material : PointerProperty(type=bpy.types.Material)
    name : StringProperty(
            default="Foo", 
            get=get_name, 
            set=set_name)

Note the example code uses the material name in list UI class. Change to show item in draw method to show collection item name instead.

layout.prop(item, "name", text= "", emboss=False, icon_value=layout.icon(ma))

Python console code, added a new scene material slot. It is given the default name "Foo". Updating the name to "Bar", in this case via console, same if done via UI, and the setter is called. Which prints old name "Foo" and new name "Bar"

>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> s.name = "Bar"
Foo Bar

and again from "Bar" to "Choo"

>>> s.name = "Choo"
Bar Choo

But here is the "rub" re the property default value. The PropertyGroup class already has a name attribute. When a new item is first added, it doesn't use the name property default of "Foo", but rather defaults to "".

>>> C.scene.material_slots.clear()
>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> C.scene.material_slots.keys()
['']

ie collection has a material_slots[""] member rather than material_slots["Foo"] However if we set it implicitly, it picks up as expected... which is usual practice I suppose.

>>> s.name = "Foo"
Foo Foo

>>> C.scene.material_slots.keys()
['Foo']

EDIT re comment

so when I update the list element's name I need to find all objects with the original element name and then change it to the new name

For example above, to set all items with old name to new name, do this on a custom property level too. Add something like below to set_name method above.

if oldname != value:
    same = [s for s in self.id_data.material_slots
            if oldname == s.get("name", "Foo")]
    for s in same:
        s["name"] = value

To elaborate on @Hikariztw 's answer

Using the code from https://blender.stackexchange.com/a/141207/15543 as an example.

Update to the property group def.

class MaterialSlot(PropertyGroup):
    def get_name(self):
        return self.get("name", "Foo")

    def set_name(self, value):
        oldname = self.get("name", "Foo")   
        self["name"] = value
        print(oldname, value)
        
    material : PointerProperty(type=bpy.types.Material)
    name : StringProperty(
            default="Foo", 
            get=get_name, 
            set=set_name)

Note the example code uses the material name in list UI class. Change to show item in draw method to show collection item name instead.

layout.prop(item, "name", text= "", emboss=False, icon_value=layout.icon(ma))

Python console code, added a new scene material slot. It is given the default name "Foo". Updating the name to "Bar", in this case via console, same if done via UI, and the setter is called. Which prints old name "Foo" and new name "Bar"

>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> s.name = "Bar"
Foo Bar

and again from "Bar" to "Choo"

>>> s.name = "Choo"
Bar Choo

But here is the "rub" re the property default value. The PropertyGroup class already has a name attribute. When a new item is first added, it doesn't use the name property default of "Foo", but rather defaults to "".

>>> C.scene.material_slots.clear()
>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> C.scene.material_slots.keys()
['']

ie collection has a material_slots[""] member rather than material_slots["Foo"] However if we set it implicitly, it picks up as expected... which is usual practice I suppose.

>>> s.name = "Foo"
Foo Foo

>>> C.scene.material_slots.keys()
['Foo']

EDIT re comment

so when I update the list element's name I need to find all objects with the original element name and then change it to the new name

For example above, to set all items with old name to new name, do this on a custom property level too. Add something like below to set_name method above.

if oldname != value:
    same = [s for s in self.id_data.material_slots
            if oldname == s.get("name", "Foo")]
    for s in same:
        s["name"] = value
Source Link
batFINGER
  • 85.1k
  • 10
  • 114
  • 244

To elaborate on @Hikariztw 's answer

Using the code from https://blender.stackexchange.com/a/141207/15543 as an example.

Update the property group.

class MaterialSlot(PropertyGroup):
    def get_name(self):
        return self.get("name", "Foo")

    def set_name(self, value):
        oldname = self.get("name", "Foo")   
        self["name"] = value
        print(oldname, value)
        
    material : PointerProperty(type=bpy.types.Material)
    name : StringProperty(
            default="Foo", 
            get=get_name, 
            set=set_name)

Note the example code uses the material name in list UI class. Change to show item in draw method to show collection item name instead.

layout.prop(item, "name", text= "", emboss=False, icon_value=layout.icon(ma))

Python console code, added a new scene material slot. It is given the default name "Foo". Updating the name to "Bar", in this case via console, same if done via UI, and the setter is called. Which prints old name "Foo" and new name "Bar"

>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> s.name = "Bar"
Foo Bar

and again from "Bar" to "Choo"

>>> s.name = "Choo"
Bar Choo

But here is the "rub" re the property default value. The PropertyGroup class already has a name attribute. When a new item is first added, it doesn't use the name property default of "Foo", but rather defaults to "".

>>> C.scene.material_slots.clear()
>>> s = C.scene.material_slots.add()
>>> s.name
'Foo'

>>> C.scene.material_slots.keys()
['']

ie collection has a material_slots[""] member rather than material_slots["Foo"] However if we set it implicitly, it picks up as expected... which is usual practice I suppose.

>>> s.name = "Foo"
Foo Foo

>>> C.scene.material_slots.keys()
['Foo']

EDIT re comment

so when I update the list element's name I need to find all objects with the original element name and then change it to the new name

For example above, to set all items with old name to new name, do this on a custom property level too. Add something like below to set_name method above.

if oldname != value:
    same = [s for s in self.id_data.material_slots
            if oldname == s.get("name", "Foo")]
    for s in same:
        s["name"] = value