How to populate Add-In Combo Box with attributes

7555
9
Jump to solution
12-27-2013 08:52 AM
KatieGaut1
New Contributor III
Hello,
     I'm using ArcMap 10.2 and trying to populate an Add-In Combo Box with the attributes (SampleYear)0 of a layer (Stream_Temperatures).  Then, on selection of a year in the Combo Box, have those records selected.

The steps I've identified are as follows

1)  Identify and get values from the selected attribute (SampleYear) of Layer (layer = Stream_Temperatures)
2)  Display these selected years in a Combo Box
3)  On user selection of year, select this year in feature class

   I'm new to Python and programming and would love any thoughts or suggestions. 

Thanks,
Katie
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
Katie,
For unique values of SampleYear, you can dynamically extract them and populate the combo box list:
values = [row[0] for row in arcpy.da.SearchCursor(layer, ["SampleYear"])] for uniqueVal in sorted(set(values)):             self.items.append(uniqueVal)


...you know, instead of populating the list with all values in the SampleYear field of the cursor records (which contain duplicate years, if I am understanding correctly?).

If that assumption is correct, then replace this section of Jake's code (repeated below) with that provided above.
with arcpy.da.SearchCursor(layer, ["SampleYear"]) as cursor:             for row in cursor:                 self.items.append(row[0])


Wayne

View solution in original post

0 Kudos
9 Replies
JakeSkinner
Esri Esteemed Contributor
Hi Katie,

You could use the following:

import arcpy
import pythonaddins

class ComboBoxClass1(object):
    """Implementation for UserData_addin.combobox (ComboBox)"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'WWWWWW'
        self.width = 'WWWWWW'
    def onSelChange(self, selection):        
        arcpy.SelectLayerByAttribute_management(layer, "NEW_SELECTION", "NAME = " + selection)
        arcpy.RefreshActiveView()
    def onFocus(self, focused):
        self.mxd = arcpy.mapping.MapDocument('current')
        global layer
        layer = arcpy.mapping.ListLayers(self.mxd, "Stream_Temperatures")[0]
        self.items = []
        with arcpy.da.SearchCursor(layer, ["SampleYear"]) as cursor:
            for row in cursor:
                self.items.append(row[0])  
        

If the 'Stream_Temperatures' field is a TEXT field, you wlil need to change the query to:

arcpy.SelectLayerByAttribute_management(layer, "NEW_SELECTION", "NAME = '" + selection + "'")
0 Kudos
KatieGaut1
New Contributor III
Thank you JSkinn - I'll give it a try and report back.  Thanks again!

Katie
0 Kudos
T__WayneWhitley
Frequent Contributor
Katie,
For unique values of SampleYear, you can dynamically extract them and populate the combo box list:
values = [row[0] for row in arcpy.da.SearchCursor(layer, ["SampleYear"])] for uniqueVal in sorted(set(values)):             self.items.append(uniqueVal)


...you know, instead of populating the list with all values in the SampleYear field of the cursor records (which contain duplicate years, if I am understanding correctly?).

If that assumption is correct, then replace this section of Jake's code (repeated below) with that provided above.
with arcpy.da.SearchCursor(layer, ["SampleYear"]) as cursor:             for row in cursor:                 self.items.append(row[0])


Wayne
0 Kudos
KatieGaut1
New Contributor III
Hi guys,

   Argh!  Now I can't even get the add-in to load properly.  I get a syntax error in the Python window after I add the Add-In (through the Customize, Add From File). 

  File "<string>", line 1
    New Combo Box_addin.combobox=New Combo Box_addin.ComboBoxClass1()
            ^
SyntaxError: invalid syntax


Thoughts?

Thanks,
Katie
0 Kudos
KatieGaut1
New Contributor III
Amazing!  I got it to work.  What a happy camper I am right now!

One little tweak would be nice though....  At this point, when the user selects a year, it works perfectly.  BUT - the other years that were available before all disappear.  For instance, a particular station has the following years of data:  2009, 2010, 2011.  When you select 2009, the other years (2010 and 2011) are no longer displayed in the combo box.

Is there a way upon selection to keep these other years still displayed? 

Thanks guys!

Katie
0 Kudos
T__WayneWhitley
Frequent Contributor
Well, do you see the "NEW_SELECTION" param in the SelectLayerByAttributes?...try changing that to "ADD_TO_SELECTION".

Keep in mind you may also then require a button to essentially 'start over' or to clear selected features.  Maybe a better function would be to check off (are radio buttons allowed in an add-in?...or multiple selections in a combo box?) available yrs to display?

Wayne

EDIT:
Actually Katie, there's probably a better way to handle that and I may have misunderstood... I'll have to think about it.

I think what is going on is that the other items are being removed because the onFocus function is firing again after the selection executes (which of course is based on a single year)...the SearchCursor runs again and reloads the list.....based on that single year selection of course.  So now if I understand correctly, after a page (the original page definition or whatever the initial graph is based on) is initialized you need to change the graph without changing the items in the list?

EDIT AGAIN:
Curious, I have not tested the following code below and I don't assume to have full understanding, but I wonder if the problem can be circumvented by creating a dummy layer (table) in your map to base the graph selected records on, so that maintaining the orig layer that initialized the combo box list is separate?  The graph would be based on the selected set in the dummy layer (or table) and the page-defined layer could then be maintained for loading the combo box list, if that works...

...and with that premise the code would look something like this, taking out the global layer variable:

import arcpy
import pythonaddins

class ComboBoxClass1(object):
    """Implementation for UserData_addin.combobox (ComboBox)"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'WWWWWW'
        self.width = 'WWWWWW'
    def onSelChange(self, selection):
        self.mxd = arcpy.mapping.MapDocument('current')
        layer2 = arcpy.mapping.ListLayers(self.mxd, "a dummy layer")[0]       
        arcpy.SelectLayerByAttribute_management(layer2, "NEW_SELECTION", "NAME = " + selection)
        arcpy.RefreshActiveView()
    def onFocus(self, focused):
        self.mxd = arcpy.mapping.MapDocument('current')
        layer = arcpy.mapping.ListLayers(self.mxd, "Stream_Temperatures")[0]
        self.items = []
        values = [row[0] for row in arcpy.da.SearchCursor(layer, ["SampleYear"])]
        for uniqueVal in sorted(set(values)):
            self.items.append(uniqueVal)


If I'm right, at the moment the drop-down list is being used, it's dynamically populated by the onFocus function using the SearchCursor to extract unique SampleYear values.  The onSelChange function is then fired when you select an item from the list...the 'selection' (the selected SampleYear item) is passed in and fed into the SelectLayerByAttribute execution.  So, as it was written before with the global layer var, a new selection was made on the SAME layer --- this becomes a problem on successive executions with the combo box dropdown list because the onFocus function must fire again, ah but the SearchCursor dynamically populates it and now we only have records selected from 1 year (isn't the SearchCursor sensitive to the selected set?).

So I think you need to separate, segregate if you will, where the SearchCursor is reading from and where the selection for the graph is being made.  At least that is my elementary approach.  Hope that makes sense.
JakeSkinner
Esri Esteemed Contributor
Amazing!  I got it to work.  What a happy camper I am right now!

One little tweak would be nice though....  At this point, when the user selects a year, it works perfectly.  BUT - the other years that were available before all disappear.  For instance, a particular station has the following years of data:  2009, 2010, 2011.  When you select 2009, the other years (2010 and 2011) are no longer displayed in the combo box.

Is there a way upon selection to keep these other years still displayed? 

Thanks guys!

Katie


I haven't tested Wayne's suggestion, but another option would be to call the actually feature class rather than the layer in the MXD and create a Feature Layer.  Ex:

import arcpy
import pythonaddins

class ComboBoxClass1(object):
    """Implementation for UserData_addin.combobox (ComboBox)"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'WWWWWW'
        self.width = 'WWWWWW'        
    def onSelChange(self, selection):
        layer = r"C:\temp\python\test.gdb\Stream_Temperatures"
        arcpy.MakeFeatureLayer_management(layer, "Selection")
        arcpy.SelectLayerByAttribute_management("Selection", "NEW_SELECTION", "SampleYear = '" + selection + "'")
        arcpy.RefreshActiveView()            
    def onFocus(self, focused):              
        layer = r"C:\temp\python\test.gdb\Stream_Temperatures"
        self.items = []
        values = [row[0] for row in arcpy.da.SearchCursor(layer, ["SampleYear"])]
        for uniqueVal in sorted(set(values)):
            self.items.append(uniqueVal)


This will add a feature layer to the MXD with the selected features.  All of the sample years will be still be available in the combo box without having to clear the selection first.  Each selection will overwrite the feature layer within the MXD.
0 Kudos
MikeCandy
New Contributor
What line of code can I add for attaching (or binding) a class to a field for a shapefile (i.e. WOdata.shp), layer, etc. to this: I just need to be able to have a user enter data through a combobox and have the data write to the shape (in an edit session). I read the above messages, but they are slightly different. Please help thanks.

class WODate(object):
    """Implementation for woToolkit_addin.combobox_3 (ComboBox)"""
    def __init__(self):
        self.items = ["05/02/2010", "04/20/2011", "05/20/2012", "05/20/2013", "01/20/2014"]
        self.editable = False
        self.enabled = True
        self.dropdownWidth = 'WWWWWWWWWWW'
        self.width = 'WWWWWWWWWWW'
    def onSelChange(self, selection):
        pass
    def onEditChange(self, text):
        pass
    def onFocus(self, focused):
        pass
    def onEnter(self):
        pass
    def refresh(self):
        pass
0 Kudos
MikeCandy
New Contributor
What line of code can I add for attaching (or binding) a class to a field for a shapefile (i.e. WOdata.shp), layer, etc. to this: I just need to be able to have a user enter data through a combobox and have the data write to the shape (in an edit session). I read the above messages, but they are slightly different. Please help thanks.

 class WODate(object):
    """Implementation for woToolkit_addin.combobox_3 (ComboBox)"""
    def __init__(self):
        self.items = ["05/02/2010", "04/20/2011", "05/20/2012", "05/20/2013", "01/20/2014"]
        self.editable = False
        self.enabled = True
        self.dropdownWidth = 'WWWWWWWWWWW'
        self.width = 'WWWWWWWWWWW'
    def onSelChange(self, selection):
        pass
    def onEditChange(self, text):
        pass
    def onFocus(self, focused):
        pass
    def onEnter(self):
        pass
    def refresh(self):
        pass
0 Kudos