3
$\begingroup$

I'm trying to use a StringProperty on a Panel I've created but the properties can't be found. --EDIT: the bpy.props docs show custom properties on an Operator which is where I got the idea.--

I have 2 StringProperties: one that I want to be user-editable, another that will essentially be a dynamic label. Basically the second be the user-editable string with a naming convention prefix/postfix applied. Why I want to do this: the next thing in the UI (stripped for the purposes of just showing my problem) is a button that the user presses to create an instance of an object using the calculated name. Storing these strings on the panel makes sense to me because they only "exist" to render stuff to the UI. I don't need to create a whole separate object and store it in the scene like what seems to always be done in the Blender examples.

class XXX_PT_propTest(bpy.types.Panel):

    ## Side Question: why does this ID throw a [Warning: 'xxx.proptest' does not contain '_PT_' with prefix and suffix] ??
    bl_idname = "xxx.proptest"

    bl_label = "Test Panel"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_category = "Test Category"

    userAssignedName: bpy.props.StringProperty(name="<User editable>")
    calculatedName: bpy.props.StringProperty(name='<Not user editable>')

    def draw(self, context):
        lyt = self.layout
        nextRow = lyt.row()

        # When the panel opens, the following line throws this error:
        #    rna_uiItemR: property not found: xxx.proptest.userAssignedName
        nextRow.prop(self, "userAssignedName", text="---")

        nextRow = lyt.row()
        nextRow.label(text="Exported Name:")

        # When the panel opens, the following line throws this error:
        #    AttributeError: 'XXX_PT_propTest' object has no attribute 'calculatedName'
        nextRow.label(text=self.calculatedName)

        ## An operator will be added to take the calculatedName and instantiate a new custom class object with it


def register():
    bpy.utils.register_class(XXX_PT_propTest)


def unregister():
    bpy.utils.unregister_class(XXX_PT_propTest)



if __name__ == "__main__":
    register()  
```
$\endgroup$
2
  • 1
    $\begingroup$ You can't add custom properties to UI elements, you'll have to attach them to an ID type docs.blender.org/api/current/bpy.types.ID.html or a bpy.types.Bone $\endgroup$
    – Gorgious
    Commented Mar 31, 2022 at 6:32
  • $\begingroup$ The bpy.props docs show custom properties added to an Operator which isn't an ID, Bone, or PoseBone. I'm sorry to sound petulant, you've answered a few of my questions which I greatly appreciate. My frustration is solely with the 3.0 documentation which I feel has really taken a step backwards from the 2.x set. $\endgroup$
    – Spurkey
    Commented Mar 31, 2022 at 16:23

1 Answer 1

4
$\begingroup$

The distinction is that adding a property means adding it to a type that already exists, like Object; whereas using a property in an Operator is part of creating a new class from scratch. You can only add properties to existing classes that inherit from one of the three classes you mentioned in comments on your question (ID, Bone, or PoseBone); but you can create a property in any new class.

Unfortunately the bpy Properties are "magic" in that they are implemented in two steps in C and the second happens at register time -- and it only checks classes that inherit from Operator. In theory Operator and Panel should work the same but in practice magic gets in the way

For the extremely curious, the SOMETYPEProperty() functions that you import from bpy.props are, in fact, functions. When Python invokes them, they call C code that inserts a marker into the function. This is the 'deferred property' marker that shows up in some error messages. When the property is registered, the relevant bpy.ops registration function notices the deferred property marker and commits magic RNA modification. But that code seems to only run on classes derived from bpy.types.Operator or when the property is explicitly registered by adding it to an existing class.

$\endgroup$

You must log in to answer this question.

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