[Blender Python] Arrange custom property data in template_list () of UI layout

What is template_list ()?

2016-05-01_20h40_39.png

sample

test_template_list.py


# ##### BEGIN GPL LICENSE BLOCK #####
#
#  This program is free software; you can redistribute it and/or
#  modify it under the terms of the GNU General Public License
#  as published by the Free Software Foundation; either version 2
#  of the License, or (at your option) any later version.
#
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with this program; if not, write to the Free Software Foundation,
#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####

# Blender2.77a

import bpy


def creat_not_jyuufuku_name(name, name_set, num):
    new_name = ""
    if '.' in name:
        split_name = name.split('.')
        if split_name[-1].isdigit():
            new_name = ".".join(split_name[0:-1]) + ".{:03d}".format(num)
        else:
            if split_name[-1] == "":
                new_name = name + "{:03d}".format(num)
            else:
                new_name = ".".join(split_name) + ".{:03d}".format(num)
    else:
        new_name = name + ".{:03d}".format(num)
    
    if new_name in name_set:
        return creat_not_jyuufuku_name(new_name, name_set, num+1)
    
    return new_name


def get_my_string(self):
    return self["name"]

def set_my_string(self, value):
    self["name"] = value
    
    tl = bpy.context.window_manager.test_ui_list.test_list
    if len(tl) > 1:
        s = set()
        result = [x.name for x in tl if x.name in s or s.add(x.name)]
        if len(result):
            number = 1
            self["name"] = creat_not_jyuufuku_name(value, s, 1)
            
        

class MyTestGroup(bpy.types.PropertyGroup):
    name = bpy.props.StringProperty(get=get_my_string, set=set_my_string)
    int_val = bpy.props.IntProperty()

bpy.utils.register_class(MyTestGroup)

class MyCollectionProperty(bpy.types.PropertyGroup):
    active_index = bpy.props.IntProperty()
    test_list = bpy.props.CollectionProperty(type=bpy.types.MyTestGroup)
    
    def add(self):
        item = self.test_list.add()
        item.name = "name"
        item.int_val = 10
        self.active_index = len(self.test_list)-1
    
    def remove(self):
        if len(self.test_list):
            self.test_list.remove(self.active_index)
            if len(self.test_list)-1 < self.active_index:
                self.active_index = len(self.test_list)-1
                if self.active_index < 0:
                    self.active_index = 0
    
    def move(self, index1, index2):
        if len(self.test_list) < 2:
            return
        if 0 <= index1 < len(self.test_list):
            if 0 <= index2 < len(self.test_list):
                self.test_list.move(index1, index2)
                self.active_index = index2
    
    def clear(self):
        self.test_list.clear()


class MyUIListAddItemOperator(bpy.types.Operator):
    bl_idname = "view3d.my_uilist_add_item"
    bl_label = "Add Item"
    
    def execute(self, context):
        context.window_manager.test_ui_list.add()
        return {'FINISHED'}


class MyUIListRemoveItemOperator(bpy.types.Operator):
    bl_idname = "view3d.my_uilist_remove_item"
    bl_label = "Remove Item"
    
    def execute(self, context):
        context.window_manager.test_ui_list.remove()
        return {'FINISHED'}


class MyUIListMoveItemOperator(bpy.types.Operator):
    bl_idname = "view3d.my_uilist_move_item"
    bl_label = "Move Item"
    
    type = bpy.props.StringProperty(default='UP')
    
    def execute(self, context):
        ui_list = context.window_manager.test_ui_list
        if self.type == 'UP':
            ui_list.move(ui_list.active_index, ui_list.active_index-1)
        elif self.type == 'DOWN':
            ui_list.move(ui_list.active_index, ui_list.active_index+1)
        return {'FINISHED'}


class MyUIListClearItemOperator(bpy.types.Operator):
    bl_idname = "view3d.my_uilist_clear_item"
    bl_label = "Clear Item"
    
    def execute(self, context):
        context.window_manager.test_ui_list.clear()
        return {'FINISHED'}


class MY_UL_test_group_list(bpy.types.UIList):
    def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
        if self.layout_type in {'DEFAULT', 'COMPACT'}:
            layout.prop(item, "name", text="", emboss=False, icon_value=icon)
        elif self.layout_type == 'GRID':
            layout.alignment = 'CENTER'
            layout.label(text="", icon_value=icon)


class UIListTestPanel(bpy.types.Panel):
    bl_label = "UIList Test Panel"
    bl_idname = "VIEW3D_PT_ui_list_test"
    bl_space_type = "VIEW_3D"
    bl_region_type = "UI"
    
    def draw(self, context):
        layout = self.layout
        
        ui_list = context.window_manager.test_ui_list
        
        row = layout.row()
        col = row.column()
        col.template_list("MY_UL_test_group_list", "", ui_list, "test_list", ui_list, "active_index", rows=1)
        
        col = row.column(align=True)
        col.operator("view3d.my_uilist_add_item", icon='ZOOMIN', text="")
        col.operator("view3d.my_uilist_remove_item", icon='ZOOMOUT', text="")
        col.operator("view3d.my_uilist_move_item", icon='TRIA_UP', text="").type = 'UP'
        col.operator("view3d.my_uilist_move_item", icon='TRIA_DOWN', text="").type = 'DOWN'
        layout.operator("view3d.my_uilist_clear_item", text="All Clear")
        
        if len(ui_list.test_list):
            row = layout.row()
            row.prop(ui_list.test_list[ui_list.active_index], "name")
            row = layout.row()
            row.prop(ui_list.test_list[ui_list.active_index], "int_val")
        

def register():
    bpy.utils.register_class(MyCollectionProperty)
    
    bpy.utils.register_class(MyUIListAddItemOperator)
    bpy.utils.register_class(MyUIListRemoveItemOperator)
    bpy.utils.register_class(MyUIListMoveItemOperator)
    bpy.utils.register_class(MyUIListClearItemOperator)
    
    bpy.utils.register_class(MY_UL_test_group_list)
    bpy.utils.register_class(UIListTestPanel)
    
    bpy.types.WindowManager.test_ui_list = bpy.props.PointerProperty(type=MyCollectionProperty)
    

def unregister():
    del bpy.types.WindowManager.test_ui_list
    
    bpy.utils.unregister_class(UIListTestPanel)
    bpy.utils.unregister_class(MY_UL_test_group_list)
    
    bpy.utils.unregister_class(MyUIListAddItemOperator)
    bpy.utils.unregister_class(MyUIListRemoveItemOperator)
    bpy.utils.unregister_class(MyUIListMoveItemOperator)
    bpy.utils.unregister_class(MyUIListClearItemOperator)
    
    bpy.utils.unregister_class(MyCollectionProperty)
    #bpy.utils.unregister_class(MyTestGroup)


if __name__ == "__main__":
    register()

Copy and paste it into a text editor in Blender and execute it.

Execution result

2016-05-08_13h43_27.png You can add and delete data from the + and-buttons. Move the selected item with the up and down buttons. You can delete all with the All Clear button.

Commentary

A separate operator is prepared for adding and deleting data, and placed next to it so that it looks the same as other panels. When actually using it, it is better to put the remove button in a remote place.

You have to avoid duplicate names yourself.

It seems that the contents of the list are displayed at draw_item () of the MY_UL_test_group_list class. You can display it by changing "name" to "int_val".

The place where you can change directly by double-clicking is the same.

Finally

I don't think I have much chance to use template_list (), but I needed it a little, so I tried to find out how to use it.

Recommended Posts

[Blender Python] Arrange custom property data in template_list () of UI layout
Real-time visualization of thermography AMG8833 data in Python
The story of reading HSPICE data in Python
A well-prepared record of data analysis in Python
Full-width and half-width processing of CSV data in Python
UI Automation in Python
Not being aware of the contents of the data in python
List of Python code used in big data analysis
Let's use the open data of "Mamebus" in Python
Custom sort in Python3
Try scraping the data of COVID-19 in Tokyo with Python
Basic summary of data manipulation in Python Pandas-Second half: Data aggregation
[Homology] Count the number of holes in data with Python
[Blender x Python] Let's arrange a lot of Susanne neatly !!
Comparison of data frame handling in Python (pandas), R, Pig
Display UTM-30LX data in Python
Equivalence of objects in Python
UI Automation Part 2 in Python
Blender Python API in Houdini (Python 3)
Implementation of quicksort in Python
Generate 8 * 8 (64) cubes in Blender Python
A simple data analysis of Bitcoin provided by CoinMetrics in Python
Draw Sine Waves in Blender Python
Get Leap Motion data in Python.
Read Protocol Buffers data in Python3
Get data from Quandl in Python
Division of timedelta in Python 2.7 series
MySQL-automatic escape of parameters in python
Handling of JSON files in Python
Implementation of life game in Python
Hashing data in R and Python
Law of large numbers in python
Implementation of original sorting in Python
Reversible scrambling of integers in Python
Get started with Python in Blender
Custom state space model in Python
How to send a visualization image of data created in Python to Typetalk
Memo of pixel position operation for image data in Python (numpy, cv2)
JSON encoding and decoding with python
Equivalence of objects in Python
Code reading of faker, a library that generates test data in Python
Python: Preprocessing in machine learning: Handling of missing, outlier, and imbalanced data
Get the key for the second layer migration of JSON data in python