4

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

batFINGER
  • 84,216
  • 10
  • 108
  • 233
  • 1
    To see any error feedback https://blender.stackexchange.com/questions/6173/where-does-console-output-go Declare the property bpy.types.Foo.prop = BarProperty(...) outside the draw method, is most often seen in an addons register method. https://blender.stackexchange.com/questions/57306/how-to-create-a-custom-ui/57332?r=SearchResults&s=1|0.0000#57332 – batFINGER Sep 14 '21 at 11:13
  • 1
    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. – batFINGER Sep 14 '21 at 11:47

2 Answers2

4

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.

brockmann
  • 12,613
  • 4
  • 50
  • 93
Martynas Žiemys
  • 24,274
  • 2
  • 34
  • 77
  • 2
    IMO place it in the register method to define the property when the addon is registered not when it is imported. – batFINGER Sep 14 '21 at 11:24
3

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()
>>> 
batFINGER
  • 84,216
  • 10
  • 108
  • 233