3
$\begingroup$

I want to use the EnumProperty the dynamic way. I've got two dialog boxes. In the first one I'm asking for database parameters and in the second one the user has to choose between some options using a dropdown. It works with a static select EnumProperty, but not with a dynamic one.

Here are my two boxes:

class IMPORT_DATABASE(Operator):

    bl_idname = "importgis.database"  # important since its how bpy.ops.import.shapefile is constructed (allows calling operator from python console or another script)
    # bl_idname rules: must contain one '.' (dot) charactere, no capital letters, no reserved words (like 'import')
    bl_description = 'Import data from postgis database'
    bl_label = "Import database"

    host = bpy.props.StringProperty(name="Host:", default="localhost")
    port = bpy.props.StringProperty(name="Port:", default="5432")
    database = bpy.props.StringProperty(name="Database:", default="scans")
    user = bpy.props.StringProperty(name="Username:",default="postgres")
    password = bpy.props.StringProperty(name="Password:",default="postgres")

    def execute(self, context):
        bpy.ops.importgis.database_connection('INVOKE_DEFAULT', password=self.password, username=self.user, database=self.database, port=self.port, host=self.host)
        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self)

And the second dialog box:

class IMPORT_DATABASE_CONNECTION(Operator):
    bl_idname = "importgis.database_connection"  # important since its how bpy.ops.import.shapefile is constructed (allows calling operator from python console or another script)
    # bl_idname rules: must contain one '.' (dot) charactere, no capital letters, no reserved words (like 'import')
    bl_description = 'Geometry'
    bl_label = "Geometry"

    host = StringProperty(options={'HIDDEN'})
    port = StringProperty(options={'HIDDEN'})
    database = StringProperty(options={'HIDDEN'})
    username = StringProperty(options={'HIDDEN'})
    password = StringProperty(options={'HIDDEN'})

    num = EnumProperty(
        items=get_items(),
        name="Geometry",
        description="choose a geometry",
        default=None,
        options={'ANIMATABLE'},
        update=None,
        get=None,
        set=None)



    def get_items(self):
        # condata = "dbname='%s' user='%s' host='%s' password='%s'" % \
        #          (self.database, self.user, self.host, self.password)
        # try:
        #    conn = psycopg2.connect(condata)
        # except:
        #    print ("I am unable to connect to the database")
        # cur = conn.cursor()
        # cur.execute("""SELECT * FROM public.geometry_columns""")
        # rows = cur.fetchall()
        # items = []
        # for row in rows:
        # geomItems = geomItems+row[0]+"//"+row[1]+"//"+row[2]+"#"
        # geomItems = geomItems + row[0] + "#"
        # items.append(row[0],row[1],row[2])

        items = [
            ('NONE', 'None', "Flat geometry"),
            ('GEOM', 'Geometry', "Use z value from shape geometry if exists"),
            ('FIELD', 'Field', "Extract z elevation value from an attribute field"),
            ('OBJ', 'Object', "Get z elevation value from an existing ground mesh")
        ]
        return items

    def execute(self, context):
        message = "Connection"
        self.report({'INFO'}, message)
        return {'FINISHED'}

    def invoke(self, context, event):
        print("Invoke")
        self.pretty_print()
        wm = context.window_manager
        return wm.invoke_props_dialog(self)

Maybe I can't find a way to build the select options in this way. I still get this error:

File "C:\Blender\2.79\scripts\modules\addon_utils.py", line 331, in enable mod = import(module_name) File "C:\Users\R62ad002\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\BlenderGIS-master__init__.py", line 45, in from .operators import * #see operators/init/all File "C:\Users\R62ad002\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\BlenderGIS-master\operators\io_import_database.py", line 74, in class IMPORT_DATABASE_CONNECTION(Operator): File "C:\Users\R62ad002\AppData\Roaming\Blender Foundation\Blender\2.79\scripts\addons\BlenderGIS-master\operators\io_import_database.py", line 86, in IMPORT_DATABASE_CONNECTION num = EnumProperty(items=get_items, name="Geometry") NameError: name 'get_items' is not defined

Can someone help me?

$\endgroup$
  • $\begingroup$ Couple of things from quick look. The items callback needs two arguments, get_items(self, context) where self is the object the enum is on (the operator in this case). Should be an error message to explain such. For the commented part if cant connect to server still need to return a list. $\endgroup$ – batFINGER Nov 13 '18 at 13:34
  • $\begingroup$ I´ve changed the def get_items(self): to def get_items(self, context):, but i still get the same error: NameError: name 'get_items' is not defined $\endgroup$ – AndyLicht Nov 13 '18 at 14:04
  • $\begingroup$ num = EnumProperty(items=get_items, name="Blah") Pass the method not the return value. for a dynamic property. See docs. $\endgroup$ – batFINGER Nov 13 '18 at 14:08
  • $\begingroup$ i get the same error by changing to EnumProperty(items=get_items... $\endgroup$ – AndyLicht Nov 13 '18 at 14:13
  • $\begingroup$ Note that you have to keep a reference to the enum items, otherwise you can get weird behaviour in Blender (even crashes). See the red box here: docs.blender.org/api/current/… $\endgroup$ – B.Y.O.B. Nov 14 '18 at 19:48
4
$\begingroup$

Fixes to question code.

  • define items as a method items=get_items, not what is returned items=get_items() See Documentation

  • The items method requires two arguments self and context

  • Ensure the items method is defined before assigning argment to it Not doing so will result in

    NameError: name 'get_items' is not defined

Code

import bpy
from bpy.props import StringProperty, EnumProperty

class ImportDataBaseConnection(bpy.types.Operator):
    bl_idname = "importgis.database_connection" 
    bl_description = 'Import Geometry Data'
    bl_label = "Geometry"

    host = StringProperty(options={'HIDDEN'})
    port = StringProperty(options={'HIDDEN'})
    database = StringProperty(options={'HIDDEN'})
    username = StringProperty(options={'HIDDEN'})
    password = StringProperty(options={'HIDDEN'})

    def item_callback(self, context):
        return (
            ('NONE', 'None', "Flat geometry"),
            ('GEOM', 'Geometry', "Use z value from shape geometry if exists"),
            ('FIELD', 'Field', "Extract z elevation value from an attribute field"),
            ('OBJ', 'Object', "Get z elevation value from an existing ground mesh"),
        )

    geo_type = EnumProperty(
        items=item_callback,
        name="Geometry Type",
        description="choose a geometry",
        default=None,
        options={'ANIMATABLE'},
        update=None,
        get=None,
        set=None)

    def execute(self, context):
        message = "Connection"
        self.report({'INFO'}, message)
        return {'FINISHED'}

    def invoke(self, context, event):
        wm = context.window_manager
        return wm.invoke_props_dialog(self, width=500)


def register():
    bpy.utils.register_class(ImportDataBaseConnection)


def unregister():
    bpy.utils.unregister_class(ImportDataBaseConnection)


if __name__ == "__main__":
    register()

    # test call
    bpy.ops.importgis.database_connection('INVOKE_DEFAULT')

Made a minimal working example, run in test editor, pops up dialog with enum items from the update method.

$\endgroup$
  • $\begingroup$ Thanks for akk this great help. These examples solve my problems. $\endgroup$ – AndyLicht Nov 15 '18 at 6:19
  • $\begingroup$ Goon on ya mate. Got there in the end. .. If the database is unlikely to be updated while using in blender may be a better option (avoid a lot of pointless queries to db when ENUM is being drawn) to populate items with items=get_items() once on register. ( Later can manually update if required with another operator that re-registers the ENUM ). The default can then be set to default = 'NONE'. Had a similar with ENUM being populated with gvim --serverlist (albeit to a Scene property rather than Operator) and found blender could become sluggish when a dynamic ENUM. $\endgroup$ – batFINGER Nov 15 '18 at 6:58

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.