2
$\begingroup$

I'm currently udpating some 2.7x script for 2.8. Everything is going fine except for one thing:

Currently the script uses a class to store some properties like so:

class MySettings(PropertyGroup):

lockHead = BoolProperty(
    name="Enable or Disable",
    description="Lock the head position of the bone",
    default = False
    )

which is registered in the registration part:

def register():
    bpy.types.Scene.my_tool = PointerProperty(type=MySettings)

def unregister():
    del bpy.types.Scene.my_tool

The issue is, Blender 2.8 doesn't want to register it in the Scene. I try to register it in the Window like so :

def register():
    bpy.types.Window.my_tool = PointerProperty(type=MySettings)

def unregister():
    del bpy.types.Window.my_tool

But then I can't get the property elsewhere (if I get it with context.window.my_tool I just have some weird tuple and can't reach the property itself). Here's an example where I try to get them in a separate UI class:

def draw (self, context):

    layout = self.layout

    mytool = context.window.my_tool

    rows = 2
    row = layout.row(align=True)
    row.prop(mytool, "lockHead",  icon='NDOF_DOM', text="Head")

So the question is, where can I register the PropertyGroup class so I can access the properties inside in an other class? Or am I doing something commpletly wrong?

And side question, since the classes are no longer stored in the bpy.types "class", how can I get them?

$\endgroup$
2
$\begingroup$

Annotations in 2.80

Not sure of the problem here. 2.8 uses annotations, currently not doing so produces a warning message.

Test code to confirm operation in 2.80

import bpy

class MySettings(bpy.types.PropertyGroup):
    # use an annotation
    lockHead : bpy.props.BoolProperty(
        name="Enable or Disable",
        description="Lock the head position of the bone",
        default=False
        )

def register():
    bpy.utils.register_class(MySettings)
    bpy.types.Scene.my_tool = bpy.props.PointerProperty(type=MySettings)

if __name__ == "__main__":
    register()
    print(bpy.context.scene.my_tool.lockHead)

Test in console:

>> C.scene.my_tool
bpy.data.scenes['Scene'].my_tool

>>> C.scene.my_tool.lockHead
False

>>> C.scene.my_tool.lockHead = True
>>> C.scene.my_tool.lockHead
True

Trying on bpy.types.Window is an issue. The use of bpy.props is restricted to ID types. As a rule of thumb objects in the bpy.data collections are ID type.. Scene type in bpy.data.scenes. There is no bpy.data.windows for the Window type. (there is the window manager)

>>> isinstance(C.window, bpy.types.ID)
False

>>> isinstance(C.window_manager, bpy.types.ID)
True

>>> bpy.types.WindowManager.my_tool = bpy.types.Scene.my_tool
>>> C.window_manager.my_tool.lockHead
False

Only a rule of thumb test, as shown by a pose bone.

>>> bpy.types.PoseBone.my_tool = bpy.types.Scene.my_tool
>>> C.active_pose_bone
bpy.data.objects['Armature'].pose.bones["Bone"]

>>> C.active_pose_bone.my_tool.lockHead
False

>>> isinstance(C.active_pose_bone, bpy.types.ID)
False

A more robust test, If a blender object doesn't support ID properties, it cannot be used to store custom properties defined with bpy.props

>>> C.window["x"] = 3
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: bpy_struct[key] = val: id properties not supported for this type
$\endgroup$
  • $\begingroup$ Thanks a lot for your very complete answer, I understand a bit better the different types now. The code you gave works well and I found, by comparing, a typo in my code that was at fault... Thanks again everything works fine now ! So if somebody comes one day here, don't forget the () in register() :D $\endgroup$ – Yadoob Dec 31 '18 at 10:59
1
$\begingroup$

An important part of using bpy.types.PropertyGroup class, is you have to register it before you use a bpy.props.PointerProperty on it.
I prefer to register it right after creation:

class MySettings(PropertyGroup):
    prop = BoolProperty()
bpy.utils.register_class(MySettings)
MySettings = bpy.props.PointerProperty(type=MySettings)
    # bpy.types.Scene.MySettings = bpy.props.PointerProperty(type=MySettings)
...

You could essentially place that under the AddonPreferences class, to create prop groups there or even inside an Operator class.
The only reason I can think of where you MUST place anything in register() would be if you wanted to run the commands after the .py file is loaded (to maintain the commonly used "register" name).

$\endgroup$
  • 2
    $\begingroup$ It's a matter of good practice vs personal preference. The modules register() method is called when as an addon it is enabled, and unregister() when it is disabled. The idea is to have the addons registered types available when the addon is enabled, and clean up when it is disabled. If put outside as suggested above they will be registered for instance when the app imports the addon as a fake module to investigate its bl_info dictionary for addons list in prefs. Also please look to the question where it specifies the 2.8 version where annotations are used. $\endgroup$ – batFINGER Mar 1 at 7:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.