5
$\begingroup$

I have an enum in my panel and I wonder how I can populate it from a file and then refresh it when needed instead of being static as shown below.

So if I have a text file populate.txt with the below format it should give the same result as the above one so that the values in the text file will be populated in my panel when it's loaded:

populate.txt:
1.5,A, 
2.4,B, 
-5.2,C, 

I also wonder how I can refresh the list after the panel is already drawn and the enum is drawn (read from the text file and update the list).

This is my current script:

import bpy
from bpy.types import Panel, PropertyGroup
from bpy.props import EnumProperty, PointerProperty
from bpy.types import Scene

bl_info = {
    "name": "prop",
    "description": "prop",
}


class PropVal(PropertyGroup):
    enumv = EnumProperty(
        name="my_enum_name:",
        description="my_enum_description",
        items=[ ("1.5", "A", ""),
                ("2.4", "B", ""),
                ("-5.2", "C", ""),
               ]
        )

class EnumPanel(Panel):
    bl_idname = "EnumPanel"
    bl_label = "Panel"
    bl_space_type = "VIEW_3D"   
    bl_region_type = "TOOLS"    
    bl_category = "Tools"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        enumval = scene.enumval
        layout.prop(enumval, "enumv")

def register():
    bpy.utils.register_module(__name__)
    bpy.types.Scene.enumval = PointerProperty(type=PropVal)

def unregister():
    bpy.utils.unregister_module(__name__)
    del bpy.types.Scene.enumval

if __name__ == "__main__":
    register()

And this is my result:enter image description here

$\endgroup$
2
$\begingroup$

bpy.props.EnumProperty can be of static nature (as in your example) or dynamic.

bpy.props.EnumProperty(items, name="", description="", default=None, options={'ANIMATABLE'}, update=None, get=None, set=None)

A dynamic enum is one whose items are calculated when clicked on, for example.

def items_file(self, context):
    items = []
    # open file
    # construct a tuple
    # append to items
    return items

Now whenever you click the enum property in the Panel, the items will be fetched from the callback.

Note:

  1. The default parameter must be None for dynamic enum
  2. In the callback, the items must always be assigned to a local variable, populated and then returned (to avoid crash: and this is a documented bug)

https://docs.blender.org/api/current/bpy.props.html

$\endgroup$
  • $\begingroup$ Thank you, it's working now reading from the file but it doesn't update unless I run the script again, any advice? the script is found here pasteall.org/429989 $\endgroup$ – Tak Jun 8 '17 at 3:07
  • $\begingroup$ I am not aware of a way to dynamically update the enum. Maybe you can add an operator button that could refresh the enum. That is what i can think of. $\endgroup$ – satishgoda Jun 9 '17 at 16:27
  • 1
    $\begingroup$ A normal enum will fetch the new items when it gets opened. To update the set of items, why not try using the update-hook ? $\endgroup$ – Teck-freak Aug 13 '17 at 18:49
0
$\begingroup$

Like that:

MyEnum= bpy.props.EnumProperty( items = get_items);

def get_items(self, context):
    l = [];
    with open('populate.txt', 'r') as f:
        for line in f:
            s = line.split(',')
            l.append((s[0], s[1], s[1]))
    return l;
$\endgroup$
  • 3
    $\begingroup$ Please add further explanation for how and why this code works, and why it answers the question. Refrain from posting nothing but a code snippet. Adding an explanation for how the code works allow for people to understand it properly and easily edit it to suit their needs. $\endgroup$ – FreemoX Aug 2 '17 at 16:33
0
$\begingroup$

And in your class "EnumPanel(Panel):" have you add this:

def check(self, context):
    return True

and you too can add an init() function for pre-calculate something....

$\endgroup$
0
$\begingroup$

Given the fact that you want to get the items from a file, why not add a string property to store the file path. When the file path is updated it can be used to update the enumerated list. enter image description here

import bpy
import csv
from bpy.types import Operator
from bpy.types import Panel

bl_info = {
    "name": "Blank1",
    "author": "Your Name Here",
    "version": (1, 0),
    "blender": (2, 79, 0),
    "location": "View3D > Tools panel 'T' > Blank1 > Blank2",
    "description": "",
    "warning": "",
    "wiki_url": "",
    "category": "",
    }


def update_selected(self, context):
    print("file : ", context.scene.csv_file)
    print("list item : ", context.scene.enum_list1)
    return None


def update_enum_list(self, context):
    enum_list_from_all(self, context)
    return None


def enum_list_from_all(self, context):
    """EnumProperty callback"""
    enum_items = []
    objs = importCSV(context.scene['csv_file'])
    if objs is None:
        return enum_items
    count = 0
    for obj in objs:
        identifier = str(obj)
        name = str(obj)
        description = str(obj)
        number = count
        enum_items.append((identifier, name, description, number))
        count += 1
    return enum_items

# Function to import CSV file data
# This is based on CSV file having a header row
# with the descriptions 'x', 'y', 'z'


def importCSV(csv_file):
    obj_loc = ()
    obj_data = ()
    objs = []
    with open(csv_file) as csvfile:
        reader = csv.DictReader(csvfile)
        for row in reader:
            obj_loc = (float(row['x']), float(row['y']), float(row['z']))
            obj_data = (obj_loc)
            objs.append(obj_data)
    return objs


class VIEW3D_PT_Blank1_Blank2(Panel):
    bl_space_type = 'VIEW_3D'
    bl_region_type = 'TOOLS'
    bl_category = "Blank1"
    bl_context = "objectmode"
    bl_label = "Blank2"

    def draw(self, context):
        layout = self.layout
        scene = context.scene
        row = layout.row()
        col = layout.column(align=True)
        col.label(text="Blank2")
        col.prop(scene, "csv_file")
        if not scene.csv_file:
            col.label(text="select a file to load")
        else:
            col.prop(scene, "enum_list1")


def register():
    bpy.utils.register_class(VIEW3D_PT_Blank1_Blank2)
    bpy.types.Scene.csv_file = bpy.props.StringProperty(
        name="csv_file",
        description="Path of CSV File to read from",
        default="",
        options={'HIDDEN'},
        update=update_enum_list,
        subtype='FILE_PATH')
    bpy.types.Scene.enum_list1 = bpy.props.EnumProperty(
        items=enum_list_from_all,
        name="enum_list1",
        description="",
        default=None,
        update=update_selected,
        )


def unregister():
    bpy.utils.unregister_class(VIEW3D_PT_Blank1_Blank2)
    del bpy.types.Scene.csv_file
    del bpy.types.Scene.enum_list1

if __name__ == "__main__":
    register()
$\endgroup$

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.