4
$\begingroup$

I am new to writing UI for Blender (2.92) and I am having a really difficult time understanding what is going on. I would like to add a panel for integer input by the user. When I look at reference code snippets they don't make sense to me and copying these bits of code across also doesn't seem to work.

I would appreciate some help in this regard so I can figure out what I have to do here. The examples I have attached are some last desperate attempts to copy across work from other examples found on the web (marked as blue) + the panel I am working on with a blue dashed line showing where I would like to display a user input.

A description would be nice instead of a vague example. I actually want to understand what is happening.

import bpy
from bpy.types import Panel

from bpy.props import IntProperty

class SMG_PT_Buttons(Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_label = "SMG Naming Button"
    bl_category = "SMG"
    bl_idname = "smg.naming"


    
    def draw(self, context):
        layout = self.layout
        bpy.types.Scene.my_use_x = bpy.props.IntProperty()

        # Button 1

        layout.label(text="Parent Object")

        row = layout.row()
        row.operator('smg.write_region', text = "Write Regions")

        row = layout.row()
        row.prop(context.scene, 'my_use_x')

        row = layout.row()
        row.operator('smg.write_territory', text = "Write Territories")

Panel I am working on

$\endgroup$
2
  • 1
    $\begingroup$ To see any error feedback blender.stackexchange.com/questions/6173/… Declare the property bpy.types.Foo.prop = BarProperty(...) outside the draw method, is most often seen in an addons register method. blender.stackexchange.com/questions/57306/… $\endgroup$
    – batFINGER
    Sep 14, 2021 at 11:13
  • 1
    $\begingroup$ Ok will comment since the question was closed. Answer gives a fix, Reasons behind: If you look in console when viewing panel AttributeError: pyrna_struct_meta_idprop_setattro() can't set in readonly state 'Scene.my_use_x' ie you cannot set (or declare ID types properties from within a draw method. context.scene.my_use_x = 10 will throw the same error. There is also a warning on running script Warning: 'smg.naming' doesn't contain '_PT_' with prefix & suffix suggesting you leave out bl_idname, defaulting to the class name, which in this case follows the naming convention. $\endgroup$
    – batFINGER
    Sep 14, 2021 at 11:47

2 Answers 2

4
$\begingroup$

Just declare your scene property in register() and remove it in unregister():

import bpy
from bpy.types import Panel
from bpy.props import IntProperty

class SMG_PT_Buttons(Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_label = "SMG Naming Button"
    bl_category = "SMG"
    bl_idname = "smg.naming"
    
    def draw(self, context):
        layout = self.layout
        
        layout.label(text="Parent Object")
        row = layout.row()
        row.operator('smg.write_region', text = "Write Regions")
        row = layout.row()
        row.prop(context.scene, 'my_use_x')
        row = layout.row()
        row.operator('smg.write_territory', text = "Write Territories")


def register():
    bpy.types.Scene.my_use_x = bpy.props.IntProperty()
    bpy.utils.register_class(SMG_PT_Buttons)

def unregister():
    bpy.utils.unregister_class(SMG_PT_Buttons)
    del bpy.types.Scene.my_use_x

if __name__ == "__main__":
    register()

As for detailed explanation, I can't think of much to say - the scene is not inside the panel, so its properties live outside panels as well, that's all.

$\endgroup$
1
  • 2
    $\begingroup$ IMO place it in the register method to define the property when the addon is registered not when it is imported. $\endgroup$
    – batFINGER
    Sep 14, 2021 at 11:24
3
$\begingroup$

Look for errors.

On running a script in blender always keep an eye on the system console

Where does console output go

After adding a call to register this class

bpy.utils.register_class(SMG_PT_Buttons)    

a warning is printed.

register_class(...):
Warning: 'smg.naming' doesn't contain '_PT_' with prefix & suffix

Suggest you leave out bl_idname, defaulting to the class name, which in this case follows the naming convention. To find this registered class

bpy.types.SMG_PT_Buttons

names like "smg.foobar" are for operators --> bpy.ops.smg.foobar(..) Another option is to

class SMGButtonsPanel(Panel):
    bl_idname = "SMG_PT_buttons"
    ...

if you prefer having your own class names,

Draw methods are read only.

You cannot declare or set an ID object property from within a draw method.

On viewing the panel

Python: Traceback (most recent call last):
  File "/Text.003", line 17, in draw
AttributeError: pyrna_struct_meta_idprop_setattro() can't set in readonly state 'Scene.my_use_x'

hence as shown in other answer declare the property from within your register method.

import bpy
from bpy.types import Panel
from bpy.props import IntProperty

class SMG_PT_Buttons(Panel):
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    bl_label = "SMG Naming Button"
    bl_category = "SMG"

    
    def draw(self, context):
        layout = self.layout
       
        # Button 1

        layout.label(text="Parent Object")

        row = layout.row()
        row.operator('smg.write_region', text = "Write Regions")

        row = layout.row()
        row.prop(context.scene, 'my_use_x')

        row = layout.row()
        row.operator('smg.write_territory', text = "Write Territories")
        
def register():
    bpy.utils.register_class(SMG_PT_Buttons)
    bpy.types.Scene.my_use_x = IntProperty()
  
  
def unregister():
    bpy.utils.unregister_class(SMG_PT_Buttons)
    del bpy.types.Scene.my_use_x
    
if __name__ == "__main__":
    register()

Test via python console.

If I have script above as blender textblock "Text.003" I can emulate importing and registering in the python console

>>> m = D.texts['Text.003'].as_module()
>>> m.register()
register_class(...):
Warning: 'smg.naming' doesn't contain '_PT_' with prefix & suffix

Whoops, forgot to take out the idname, edit go again

>>> m = D.texts['Text.003'].as_module()
>>> m.register()
>>> m.unregister()
>>> 
$\endgroup$

You must log in to answer this question.

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