From the print statements in localUpdate
it appears that changing the value of localString
in the Redo
panel updates globalString
but globalString
is not actually updated. What am I missing? (This doesn't seem to be a Blender bug, but something I'm not understanding about StringProperty
or properties in general.)
NOTE: This is a a question about why the update function doesn't work, not about how to update the global without using the update function. I've simplified a fairly complex setup that has mixins that modify the local to get to this example, so while updating the global in execute
would work in the example, it won't work in the final system.
To see the problem, invoke the operator by using the button in the tla Panel. When the Last Operator Adjustment (redo) panel shows up, change the value of localString
in the panel. Messages will appear on the system console showing that localUpdate
has run and modified globalString
but if you check bpy.context.scene.globalString
in the Python console after making the change, it will still have its original value of "global". Further, setting its value in the Python console causes it to change in the panel.
Here is the add-on. Copy it into the text editor and hit run.
import bpy
from bpy.types import Operator, Panel
from bpy.props import StringProperty
bl_info = {
"name" : "Op Test",
"description" : "a test",
"author" : "Marty",
"version" : (0, 0, 1),
"blender" : (2, 80, 0),
"location" : "View3D",
"support" : "COMMUNITY",
"category" : "3D View"
}
class TLA_OT_message(Operator):
bl_idname = "tla.message"
bl_label = "An Op"
bl_options = {"REGISTER", "UNDO"}
def localUpdate(self, context):
print("localUpdate called")
print(self.localString)
print(f'before {bpy.context.scene.globalString}')
context.scene.globalString = self.localString
print(f' after {bpy.context.scene.globalString}')
localString : bpy.props.StringProperty(
name="localString",
default="local",
update=localUpdate)
def execute(self, context):
self.report({"INFO"}, f"local string is {self.localString}")
return {"FINISHED"}
class TL_PT_panel(Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
bl_category = "tla"
bl_label = "Panel"
bl_options = set()
def draw(self, context):
col = self.layout.column()
col.operator(TLA_OT_message.bl_idname, text = "push me")
col.prop(context.scene, "globalString", text="Global")
def anUpdater(self, context):
print("an Updater called")
def register():
bpy.utils.register_class(TLA_OT_message)
bpy.utils.register_class(TL_PT_panel)
bpy.types.Scene.globalString = bpy.props.StringProperty(
name="globalString",
default = "global",
update=anUpdater,
)
def unregister():
del bpy.types.Scene.globalString
bpy.utils.unregister_class(TL_PT_panel)
bpy.utils.unregister_class(TLA_OT_message)
if __name__ == "__main__":
register()
Here is what the 3D Viewport looks like after installing the addon, opening the side panel, selecting the 'tla' tab, and pushing the button:
Change "local" to "other" and the info message in the info window changes:
bpy.ops.text.run_script()
bpy.ops.tla.message()
local string is local
bpy.data.window_managers["WinMan"].(null) = "other"
bpy.ops.tla.message(localString="other")
local string is other
(Icons don't copy so here's a screenshot)
and the content of the system console at this point:
Read prefs: C:\Users\stupi\AppData\Roaming\Blender Foundation\Blender\2.93\config\userpref.blend
Read blend: D:\stupi\blender\blends\stack exchange answers\updater test.blend
Info: local string is local
localUpdate called
other
before global
an Updater called
after other
Info: local string is other
Finally, checking the value of bpy.context.scene.globalString
after all of that:
PYTHON INTERACTIVE CONSOLE 3.9.2 (default, Mar 1 2021, 08:18:55) [MSC v.1916 64 bit (AMD64)]
Builtin Modules: bpy, bpy.data, bpy.ops, bpy.props, bpy.types, bpy.context, bpy.utils, bgl, blf, mathutils
Convenience Imports: from mathutils import *; from math import *
Convenience Variables: C = bpy.context, D = bpy.data
>>> bpy.context.scene.globalString
'global'
>>>
and for completeness: my test file: