Im trying to figure out why this CollectionProperty which has a PropertyGroup for a custom UI list, doesnt want to load from from blender startup.
Ive found this code and works fine when a scene i open and used in text area to register it. All works and it shows up.
import bpyimport os
coll_data = (
("Option A", "The first option, can be found by searching '1' as well"),
("Option B", "You can find this by searching for 'roflmao'"),
("Some text", "Some more descriptive explanation"),
("Blabla", "Talking stuff...")
)
class COLL_UL_search(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
# You should always start your row layout by a label (icon + text), or a non-embossed text field,
# this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
# We use icon_value of label, as our given icon is an integer value, not an enum ID.
# Note "data" names should never be translated!
split = layout.split(0.3)
split.label(item.label)
split.label(item.description)
elif self.layout_type in {'GRID'}:
pass
class MyColl(bpy.types.PropertyGroup):
#name = bpy.props.StringProperty()
label = bpy.props.StringProperty()
description = bpy.props.StringProperty()
class HelloWorldPanel(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "Hello World Panel"
bl_idname = "OBJECT_PT_hello"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "scene"
def draw(self, context):
layout = self.layout
col = context.scene.col
idx = context.scene.col_idx
if idx >= len(col):
#context.scene.col_idx = len(col) - 1
text = "(index error)"
else:
text = col[idx].name
layout.template_list("COLL_UL_search", "", context.scene, "col", context.scene, "col_idx")
def collhack(scene):
bpy.app.handlers.scene_update_pre.remove(collhack)
try:
scene.col.clear()
except:
pass
for i, (label, description) in enumerate(coll_data, 1):
item = scene.col.add()
item.label = label
item.description = description
item.name = " ".join((str(i), label, description))
def register():
bpy.utils.register_module(__name__)
bpy.types.Scene.col = bpy.props.CollectionProperty(type=MyColl)
bpy.types.Scene.col_idx = bpy.props.IntProperty(default=0)
bpy.app.handlers.scene_update_pre.append(collhack)
def unregister():
bpy.utils.unregister_module(__name__)
del bpy.types.Scene.col
del bpy.types.Scene.col_idx
if __name__ == "__main__":
register()
Now i wanted to add my own items. The list i need is from a different render engine i use which can have linked materials. Ive added a function which checks if the links working and if not return a list of missing materials, material name, meshname.
The problem is the registration now. The collectionProperty āScene.col_itemā doesnt want to register. I also see this error in the console.
TypeError: CollectionProperty(...): expected an RNA type derived from PropertyGroup, failed with: RuntimeError: , missing bl_rna attribute from 'RNAMetaPropGroup' instance (may not be registered)
Traceback (most recent call last):
File "/Applications/Blender/blender.app/Contents/MacOS/../Resources/2.78/scripts/modules/addon_utils.py", line 330, in enable
mod = __import__(module_name)
File "/Users/romboutversluijs/Library/Application Support/Blender/2.78/scripts/addons/TheaForBlender/__init__.py", line 58, in <module>
from . import thea_operators
File "/Users/romboutversluijs/Library/Application Support/Blender/2.78/scripts/addons/TheaForBlender/thea_operators.py", line 3187, in <module>
type=MyColl
ValueError: bpy_struct "Scene" registration error: col_item could not register
My adjusted code is like this
def checkRelinkTheaExtMat(): '''check if Thea linked materials are live
:return: False if missing link
:rtype: bool
'''
missing_Materials = []
matNameExt = ""
matMesh = ""
matExtLink = True
sceneLoaded = False
try:
if bpy.context.scene:
sceneLoaded = True
else:
missing_Materials.append(("Nothing loaded", ""))
except:
pass
if sceneLoaded:
for mat in bpy.data.materials:
if getattr(mat, "thea_extMat"):
extMat = os.path.exists(os.path.abspath(bpy.path.abspath(mat.get('thea_extMat'))))
if extMat == False:
# matMesh = bpy.context.active_object.name
matExtLink = False
matNameExt = mat.name
MNAME = matNameExt
obs = []
for o in bpy.data.objects:
if isinstance(o.data, bpy.types.Mesh) and MNAME in o.data.materials:
# obs.append(o.name)
matMesh = o.name
# missing_Materials.append("%s > Mesh obj: %s" % (matNameExt, matMesh))
missing_Materials.append((matNameExt, matMesh))
# return [matExtLink, matNameExt, matMesh]
else:
pass
missing_Materials = sorted(list(set(missing_Materials)))
else:
pass
# print("*** Missing Material list: %s" % missing_Materials)
return [matExtLink, matNameExt, matMesh, missing_Materials]
class COLL_UL_search(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if self.layout_type in {'DEFAULT', 'COMPACT'}:
# You should always start your row layout by a matname (icon + text), or a non-embossed text field,
# this will also make the row easily selectable in the list! The later also enables ctrl-click rename.
# We use icon_value of matname, as our given icon is an integer value, not an enum ID.
# Note "data" names should never be translated!
if not checkRelinkTheaExtMat()()[1]:
layout.matname("Yeah all material linked")
else:
row = layout.split(1)
row = layout.row(align=True)
row.label("", icon='MATERIAL')
row.label(item.matname)
row = layout.row(align=True)
row.prop(bpy.data.materials[item.matname], "thea_extMat","")
row.operator("open.thea_files", text="", icon='FILESEL')
try:
if (os.path.exists(os.path.abspath(bpy.path.abspath(bpy.data.materials[item.matname].get('thea_extMat')))))==False:
row.label(text="Missing link!", icon='ERROR')
except:
pass
elif self.layout_type in {'GRID'}:
pass
class RelinkMissingMaterials(bpy.types.Panel):
"""Creates a Panel in the Material Tab"""
bl_label = "Relink Missing Materials"
bl_idname = "OBJECT_PT_relink_missing_materials"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "materials"
def draw(self, context):
layout = self.layout
thea_globals.log.debug("List missing; %s" % layout)
col_item = context.scene.col_item
idx = context.scene.col_idx
if idx >= len(col_item):
# context.scene.col_idx = len(col_item) - 1
text = "(index error)"
else:
text = col_item[idx].name
layout.template_list("COLL_UL_search", "", context.scene, "col_item", context.scene, "col_idx")
class MyColl(bpy.types.PropertyGroup):
#name = bpy.props.StringProperty()
matname = bpy.props.StringProperty()
matpath = bpy.props.StringProperty()
def collhack(scene):
# bpy.app.handlers.scene_update_pre.remove(collhack)
try:
scene.col_item.clear()
except:
pass
for i, (matname, matpath) in enumerate(checkRelinkTheaExtMat()[3], 1):
item = scene.col_item.add()
item.matname = matname
item.matpath = matpath
item.name = " ".join((str(i), matname, matpath))
#def sceneLoaded(context):
# Scene = bpy.types.Scene
# try:
# if context.scene:
## scene = bpy.context.scene
# sceneLoaded = True
# except:
# pass
# if context:
Scene = bpy.types.Scene
Scene.col_item = bpy.props.CollectionProperty(
type=MyColl
)
Scene.col_idx = bpy.props.IntProperty(
default=0
)
# bpy.app.handlers.scene_update_pre.append(collhack)
collhack(bpy.context.scene)
# print("scene items:%s" % item.matname)
I also tried adding the registration of the bottom 3 to register part in the main addon but it doesnt work as well.
What can i change to get this to work?