Friday 8 April 2016

arcpy - Using two Python Addin Combo Boxes to choose feature class first then field from chosen feature class?


Last night a student from my Udemy course about writing Python AddIns asked for:



some tips for using a combo box to filter another combo box. What I am trying to do is use a combo box to select my [feature class], which I've managed to do. Once that combo box is selected, I want the second box to show all the fields in that [feature class], which I can then go ahead and select to perform further analysis on.



I think the key to doing this may be found in code from @sur's answer (with help from Freddie Gibson of Esri) to Dynamically adding items into one python addin Combobox from another?:


import arcpy

import pythonaddins

class ComboBoxClass1(object):
"""Implementation for TestCombo_addin.combobox (ComboBox)"""
def __init__(self):
self.items = ["cb1item1", "cb1item2"]
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWWW'
self.width = 'WWWWWW'

ComboBoxClass1._hook=self
def onSelChange(self, selection):
pass

class ComboBoxClass2(object):
"""Implementation for TestCombo_addin.combobox_1 (ComboBox)"""
def __init__(self):
self.items = ["cb2item1", "cb2item2"]
self.editable = True
self.enabled = True

self.dropdownWidth = 'WWWWWW'
self.width = 'WWWWWW'
def onSelChange(self, selection):
ComboBoxClass1._hook.items.append(selection)

but how do I use the _hook property of a ComboBoxClass to achieve what my student has asked for?



Answer



I think using a class property to set a hook to an instance of that class is bad practice and while it works fine here will cause you grief if you use this construct in other code. E.g. you write a class and create more than one instance of it or you have a superclass with this hook and you create multiple subclasses or multiple instances of a subclass. The hook property of the class will get overwritten each time an instance is created.


What I do is use the instances of the classes, not the classes themselves.


For example, in config.xml you will have something like:









etc...
etc...

















Note the id and refID are the same. These will refer to instances of these classes.


Then you just replace references to ComboBoxClass2 to combobox2 in your code:


import arcpy
import pythonaddins

class ComboBoxClass1(object):
"""Implementation for ComboBox_addin.combobox1 (ComboBox)"""

def __init__(self):
arcpy.env.workspace = r"C:\polygeo\QGIS"
self.items = arcpy.ListFeatureClasses()
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWWWWWWWWWWWWWWWWWWWWWWWWW'
self.width = 'WWWWWWWWWWWWWWWWWWWWWWWWWWWW'
def onSelChange(self, selection):
combobox2.items = [x.name for x in arcpy.ListFields(selection)] # <================
def onEditChange(self, text):

pass
def onFocus(self, focused):
pass
def onEnter(self):
pass
def refresh(self):
pass

class ComboBoxClass2(object):
"""Implementation for ComboBox_addin.combobox2 (ComboBox)"""

def __init__(self):
self.items = []
self.editable = True
self.enabled = True
self.dropdownWidth = 'WWWWWWWWWWWW'
self.width = 'WWWWWWWWWWWW'

def onSelChange(self, selection):
pass
def onEditChange(self, text):

pass
def onFocus(self, focused):
pass
def onEnter(self):
pass
def refresh(self):
pass

If you run into a NameError (an issue with earlier ArcGIS versions, not sure if still a problem), put the following at the bottom of ComboBox_addin.py: :


##Workaround for 'NameError: global name 'combobox2' is not defined' - https://geonet.esri.com/thread/76833

combobox1 = ComboBoxClass1()
combobox2 = ComboBoxClass2()

No comments:

Post a Comment

arcpy - Changing output name when exporting data driven pages to JPG?

Is there a way to save the output JPG, changing the output file name to the page name, instead of page number? I mean changing the script fo...