Select to view content in your preferred language

Addin Combo Box

2154
10
11-05-2013 08:44 AM
FredKellner1
Deactivated User
I have been struggling to get the combo box addin working properly on toolbars that I have created. So in attempt to better understand the combo box I have been trying to implement a combo box using the example from the documentation.

The documentation states "this topic examines the process of creating a combo box with the list of layers from the table of contents. Selecting a layer will create a fishnet covering the full extent of the layer".

And I have used the code example in the documentation

# Business logic to implement the ComboBox
def __init__(self):
        self.editable = True
        self.enabled = True

def onSelChange(self, selection):

 # When a new layer is selected, create a new fishnet using the extent of layer.
 layer = arcpy.mapping.ListLayers(self.mxd, selection)[0]
 desc = arcpy.Describe(layer.dataSource)
 extent = desc.Extent
 fishnet = arcpy.CreateFishnet_management(r'in_memory\fishnet',
                 '%f %f' %(extent.XMin, extent.YMin),
                 '%f %f' %(extent.XMin, extent.YMax),
                 0, 0, 10, 10,
                 '%f %f' %(extent.XMax, extent.YMax),
                 'NO_LABELS',
                 '%f %f %f %f' %(extent.XMin, extent.YMin, extent.XMax, extent.YMax), 'POLYGON')
 arcpy.RefreshActiveView()

def onFocus(self, focused):

  # When the combo box has focus, update the combo box with the list of layer names.
 if focused:
  self.mxd = arcpy.mapping.MapDocument('current')
  layers = arcpy.mapping.ListLayers(self.mxd)
  self.items = []
  for layer in layers:
   self.items.append(layer.name)


But I have been unable to get the toolbar to work. The toolbar shows up in arcmap but there is no drop down and I get the missing message on the toolbar itself.

Any suggestions?

Thanks

Fred
Tags (2)
0 Kudos
10 Replies
JasonScheirer
Esri Alum
try calling self.refresh() at the end of your onFocus routine.
0 Kudos
DavidSchwab
Deactivated User
I'm having the same problem. Did anyone resolve the issue. I tried to refresh as suggested but... it didn't work for me
0 Kudos
JohnDye
Deactivated User
Comboboxes are kind of finnicky. Try baby stepping it...

Replace any code contained in any of the combobox methods with a pass statement:
class MyComboBox(object):
    """Implementation for MyComboBox"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        self.width = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
    def onSelChange(self, selection):
        """Occurs when the user makes a selection from the ComboBox drop-down menu"""
        pass
    def onEditChange(self, text):
        """Occurs when the user manually enters text into the ComboBox"""
        pass
    def onFocus(self, focused):
        """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
        pass
    def onEnter(self):
        """Occurs when the user presses the 'Enter' key while the ComboBox has focus"""
        pass
    def refresh(self):
        """Occurs after a value is established within the ComboBox"""
        self.refresh()


Next, let's just make sure we can get the combobox to dynamically populate with a list of layers in the TOC when given focus
    def onFocus(self, focused):
        """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
        # Empty the Combobox items list
        self.items = []
        # Establish a reference to the current MXD
        mxd = arcpy.mapping.MapDocument("Current")
        # Establish a reference to the first DataFrame object in the current MXD
        df = arcpy.mapping.ListDataFrames(mxd)[0]
        # Build a List of LayerObjects contained in the first DataFrame of the current MXD
        Layers = arcpy.mapping.ListLayers(mxd, "*", df)
        # Iterate through the Layers
        for Layer in LayerList:
            # Append the current Layer's name to the Items List
            self.items.append(Layer.name)


Once onFocus() has been invoked and you have a list of layers populating dynamically in the Combobox, we can begin thinking about what we want to do with the Selection in the Combobox. That's where the onSelection() and onEnter() events come into play.

onEditChange() is really just another method of making a selection by allowing the user to type values directly into the box. Valuable when your item list is really long, so that the user doesn't have to scroll through values.

For this though, we'll just focus on the onSelection() method.

So now that we can make selections in the Combobox, what do we want to do with them? Let's look at onSelection()
def onSelChange(self, selection):
 # Because 'mxd' and 'df' weren't given global scope, we have to reestablish them
        # in order to use them in this method
 mxd = arcpy.mapping.MapDocument("Current")
 df = arcpy.mapping.ListDaaFrames(mxd)[0]
 # Reference the first Layer in the DataFrame of the MXD which has a name that matches
        # the current selection
 layer = arcpy.mapping.ListLayers(self.mxd, selection, df)[0]
 desc = arcpy.Describe(layer.dataSource)
 extent = desc.Extent
 fishnet = arcpy.CreateFishnet_management(r'in_memory\fishnet',
                 '%f %f' %(extent.XMin, extent.YMin),
                 '%f %f' %(extent.XMin, extent.YMax),
                 0, 0, 10, 10,
                 '%f %f' %(extent.XMax, extent.YMax),
                 'NO_LABELS',
                 '%f %f %f %f' %(extent.XMin, extent.YMin, extent.XMax, extent.YMax), 'POLYGON')
 arcpy.RefreshActiveView()


I would encourage you to implement each of these in baby steps, rebuilding and testing the addin after each change so that if you do find problems, you know where to look. Print statements can also come in very handy for this purpose.
0 Kudos
DavidSchwab
Deactivated User
Thanks John. I changed the code as you said. Each time the combo box drop down lists item 1 and item 2 in ArcMap regardless of whats in TOC. And no errors or anything shows up in my python window after trying to use the combobox. What do you think? I'm posting my code below:

import arcpy
import pythonaddins

class FishnetComboBoxClass1(object):
    """Implementation for Comboboxfishnet_addin.combobox (ComboBox)"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        self.width = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
       
    def onSelChange(self, selection):
        # Because 'mxd' and 'df' weren't given global scope, we have to reestablish them
        # in order to use them in this method
mxd = arcpy.mapping.MapDocument("Current")
df = arcpy.mapping.ListDaaFrames(mxd)[0]
# Reference the first Layer in the DataFrame of the MXD which has a name that matches
        # the current selection
layer = arcpy.mapping.ListLayers(self.mxd, selection, df)[0]
desc = arcpy.Describe(layer.dataSource)
extent = desc.Extent
fishnet = arcpy.CreateFishnet_management(r'in_memory\fishnet',
                 '%f %f' %(extent.XMin, extent.YMin),
                 '%f %f' %(extent.XMin, extent.YMax),
                 0, 0, 10, 10,
                 '%f %f' %(extent.XMax, extent.YMax),
                 'NO_LABELS',
                 '%f %f %f %f' %(extent.XMin, extent.YMin, extent.XMax, extent.YMax), 'POLYGON')

          
    def onEditChange(self, text):
        """Occurs when the user manually enters text into the ComboBox"""
        pass
   
    def onFocus(self, focused):

        """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
        # Empty the Combobox items list
        self.items = []
        # Establish a reference to the current MXD
        mxd = arcpy.mapping.MapDocument("Current")
        # Establish a reference to the first DataFrame object in the current MXD
        df = arcpy.mapping.ListDataFrames(mxd)[0]
        # Build a List of LayerObjects contained in the first DataFrame of the current MXD
        Layers = arcpy.mapping.ListLayers(mxd, "*", df)
        # Iterate through the Layers
        for Layer in LayerList:
            # Append the current Layer's name to the Items List
            self.items.append(Layer.name)
       
    def onEnter(self):
        """Occurs when the user presses the 'Enter' key while the ComboBox has focus"""
        pass

    def refresh(self):
        """Occurs after a value is established within the ComboBox"""
        self.refresh()
0 Kudos
JohnDye
Deactivated User
Hey David,
Could you edit your post by putting the code inside of code brackets to make it easier to try and find and issues with your indentations?

See this post to learn more:
http://forums.arcgis.com/threads/48475-Please-read-How-to-post-Python-code

In regards to why you're seeing item1 and item2, those are typically default listings provided by the ESRI Python Addin Template.

There's nothing in your code that should be doing that, so I would suggest going into your Addin Manager in ArcMap and ensuring that you uninstall any Addin's related to this process so that the code is removed from your assembly cache.

Then try reinstalling the addin you built from this code.
0 Kudos
DavidSchwab
Deactivated User
Please check my code. Thanks.


import arcpy
import pythonaddins

class FishnetComboBoxClass1(object):
    """Implementation for Comboboxfishnet_addin.combobox (ComboBox)"""
    def __init__(self):
        self.editable = True
        self.enabled = True
        self.dropdownWidth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        self.width = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        
    def onSelChange(self, selection):
        # Because 'mxd' and 'df' weren't given global scope, we have to reestablish them
        # in order to use them in this method
 mxd = arcpy.mapping.MapDocument("Current")
 df = arcpy.mapping.ListDaaFrames(mxd)[0]
 # Reference the first Layer in the DataFrame of the MXD which has a name that matches
        # the current selection
 layer = arcpy.mapping.ListLayers(self.mxd, selection, df)[0]
 desc = arcpy.Describe(layer.dataSource)
 extent = desc.Extent
 fishnet = arcpy.CreateFishnet_management(r'in_memory\fishnet',
                 '%f %f' %(extent.XMin, extent.YMin),
                 '%f %f' %(extent.XMin, extent.YMax),
                 0, 0, 10, 10,
                 '%f %f' %(extent.XMax, extent.YMax),
                 'NO_LABELS',
                 '%f %f %f %f' %(extent.XMin, extent.YMin, extent.XMax, extent.YMax), 'POLYGON')

           
    def onEditChange(self, text):
        """Occurs when the user manually enters text into the ComboBox"""
        pass
    
    def onFocus(self, focused):

        """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
        # Empty the Combobox items list
        self.items = []
        # Establish a reference to the current MXD
        mxd = arcpy.mapping.MapDocument("Current")
        # Establish a reference to the first DataFrame object in the current MXD
        df = arcpy.mapping.ListDataFrames(mxd)[0]
        # Build a List of LayerObjects contained in the first DataFrame of the current MXD
        Layers = arcpy.mapping.ListLayers(mxd, "*", df)
        # Iterate through the Layers
        for Layer in LayerList:
            # Append the current Layer's name to the Items List
            self.items.append(Layer.name)
        
    def onEnter(self):
        """Occurs when the user presses the 'Enter' key while the ComboBox has focus"""
        pass

    def refresh(self):
        """Occurs after a value is established within the ComboBox"""
        self.refresh()
0 Kudos
SageWall
Deactivated User
It looks like you may have an issue in the onFocus method.  You create a list of the current layers in the dataframe called "Layers" but then try to iterate though them with for Layer in LayerList.  Try changing LayerList to Layers.

def onFocus(self, focused):
    """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
    # Empty the Combobox items list
    self.items = []
    # Establish a reference to the current MXD
    mxd = arcpy.mapping.MapDocument("Current")
    # Establish a reference to the first DataFrame object in the current MXD
    df = arcpy.mapping.ListDataFrames(mxd)[0]
    # Build a List of LayerObjects contained in the first DataFrame of the current MXD
    Layers = arcpy.mapping.ListLayers(mxd, "*", df)
    # Iterate through the Layers
    for Layer in Layers:
        # Append the current Layer's name to the Items List
        self.items.append(Layer.name)
0 Kudos
JohnDye
Deactivated User
It looks like you may have an issue in the onFocus method.  You create a list of the current layers in the dataframe called "Layers" but then try to iterate though them with for Layer in LayerList.  Try changing LayerList to Layers.


Doh! That's my fault. Sorry about that Dave! Great catch Sage!
0 Kudos
DavidSchwab
Deactivated User
Thanks for the help so far guys. But I did everything the help said, I tried baby steps John, and I made your change Sage, but... the combo box still just says layer 1 and layer2 and there are no errors listed in the python window. If there were errors in the python window then I would have something to correct but I'm just not seeing a solution. hmm....

import arcpy
import pythonaddins

class FishnetComboBoxClass1(object):
    """Implementation for Comboboxfishnet_addin.combobox (ComboBox)"""
    def __init__(self):
            self.editable = True
            self.enabled = True
            self.dropdownWidth = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
            self.width = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
        
    def onSelChange(self, selection):
            mxd = arcpy.mapping.MapDocument("Current")
            df = arcpy.mapping.ListDaaFrames(mxd)[0]
            layer = arcpy.mapping.ListLayers(self.mxd, selection, df)[0]
            desc = arcpy.Describe(layer.dataSource)
            extent = desc.Extent
            fishnet = arcpy.CreateFishnet_management(r'in_memory\fishnet',
                            '%f %f' %(extent.XMin, extent.YMin),
                            '%f %f' %(extent.XMin, extent.YMax),
                            0, 0, 10, 10,
                            '%f %f' %(extent.XMax, extent.YMax),
                            'NO_LABELS',
                            '%f %f %f %f' %(extent.XMin, extent.YMin, extent.XMax, extent.YMax), 'POLYGON')
            arcpy.RefreshActiveView()

           
    def onEditChange(self, text):
            """Occurs when the user manually enters text into the ComboBox"""
            pass
    
    def onFocus(self, focused):
            """Occurs when the user clicks on the Combobox, giving the ComboBox focus"""
            self.items = []
            # Establish a reference to the current MXD
            mxd = arcpy.mapping.MapDocument("Current")
            # Establish a reference to the first DataFrame object in the current MXD
            df = arcpy.mapping.ListDataFrames(mxd)[0]
            # Build a List of LayerObjects contained in the first DataFrame of the current MXD
            Layers = arcpy.mapping.ListLayers(mxd, "*", df)
            # Iterate through the Layers
            for Layer in Layers
                self.items.append(Layer.name)
        
    def onEnter(self):
            """Occurs when the user presses the 'Enter' key while the ComboBox has focus"""
            pass

    def refresh(self):
            """Occurs after a value is established within the ComboBox"""
            self.refresh()
        
0 Kudos