Combobox Issue: When editable=false and selection entered, selection disappears

1134
5
Jump to solution
05-15-2014 12:27 PM
KatieGaut1
New Contributor III
I'm using ArcGIS 10.2.1 and have written an Arcpy addin with multiple comboboxes. I need most of my comboboxes to be non-editable. However, when I set self.editable = false and a selection is made I cannot get this selection to stay visible in the combobox. A subset of my code is below:
class ComboBoxOwnerName(object): """Implementation for QueryTool_addin.combobox_2 (ComboBox)""" def __init__(self):     self.editable = False     self.enabled = True     self.dropdownWidth = 'WWWWWWWWWWWWWWWWWWWWWWWWWWWW'     self.width = 'WWWWWWWWWWWWWWWWWW'     self.mxd = arcpy.mapping.MapDocument('current')     layer4 = arcpy.mapping.ListLayers(self.mxd, "PODs")[0]     layer4_path= layer4.dataSource     self.items = []     values = [row[0] for row in arcpy.da.SearchCursor(layer4_path, ["Person"])]     for uniqueVal in sorted(set(values)):                 self.items.append(uniqueVal)     print "__init__"  def onSelChange(self, selection):     self.mxd = arcpy.mapping.MapDocument('current')     layer1 = arcpy.mapping.ListLayers(self.mxd, "PODs")[0]     layer2 = arcpy.mapping.ListLayers(self.mxd, "POUs")[0]     arcpy.SelectLayerByAttribute_management(layer1, "NEW_SELECTION", "Person = '" + selection + "'")     arcpy.SelectLayerByAttribute_management(layer2, "NEW_SELECTION", "Person = '" + selection + "'")     df = arcpy.mapping.ListDataFrames(self.mxd)[0]     layer1.getSelectedExtent()     layer2.getSelectedExtent()     df.zoomToSelectedFeatures()     global currentselection     currentselection = selection     print currentselection     print "Ran onSelChange"     self.items = [selection]  def onEditChange(self, text):     pass def onFocus(self, focused):     pass def onEnter(self):     pass def refresh(self):     self.mxd = arcpy.mapping.MapDocument('current')     layer3 = arcpy.mapping.ListLayers(self.mxd, "PODs")[0]     self.items = [currentselection]     print "Ran refresh"


Any thoughts would be appreciated!
Tags (2)
0 Kudos
1 Solution

Accepted Solutions
T__WayneWhitley
Frequent Contributor
I'm sorry to say, although you may already realize this, what you state as your 'business logic' and your implementation attempt to accomplish said logic are not quite coherent.  I suppose we can conclude you're still in the right place, as we are all still learning.

Let me warp this conversation back to what I surmise is 'the center'.  What you say you want to do is quite easy to accomplish - but I don't want to delve too far into the details of your 'other' business logic because I think it can be hinged or added to the logic 'framework', if you will, that I show here.  Besides, it is simpler just to add to what code sample (involving a single combobox) I've already posted above - I'll repeat the code below and add-in (no pun intended) the button code....and offer a few pointers further below.
import arcpy import pythonaddins  class ButtonClass7(object):     """Implementation for testNonEditCombo_addin.button (Button)"""     def __init__(self):         self.enabled = True         self.checked = False     def onClick(self):         combobox.value = ''         combobox.refresh()  class ComboBoxClass1(object):     """Implementation for testNonEditCombo_addin.combobox (ComboBox)"""          def __init__(self):         self.editable = True         self.enabled = True         # introducing global         global staticVal         self.newfunction()         self.value = staticVal = self.items[0]              def onSelChange(self, selection):         # redefining global         global staticVal         self.value = staticVal = selection         print 'selection: {0}'.format(selection)      def onEditChange(self, text):         pass      def onFocus(self, focused):         if focused: self.newfunction()      def onEnter(self):         self.value = staticVal         print 'self.refresh...so did the refresh function fire?'         self.refresh()              def refresh(self):         arcpy.RefreshActiveView()         print 'refreshed...'      def newfunction(self):         self.mxd = arcpy.mapping.MapDocument('current')         self.items = [lyr.name for lyr in arcpy.mapping.ListLayers(self.mxd)]


So, just to add a few small explanations, here you go:

- My logic doesn't really do anything but load existing layers from the map into the combobox 'list'; add your own logic to select and zoom, whatever you want, where applicable.

- The only thing modified in the added button is the 'onClick' where you said you simply wanted to 'clear the selection' in the combobox.  See my reference to the combobox, "testNonEditCombo_addin.combobox"?  The object reference to that class is simply 'combobox'.

- Then, using that obj ref, the command to clear the box to essentially a blank value is:
combobox.value = ''

- However, you need to refresh the combobox to show it, hence the next line which calls the already existing refresh function:
combobox.refresh()

- Notice that function in the combox class simply calls the familiar refresh active view command, arcpy.RefreshActiveView()... it is the timing of the refresh execution you're interested in, so that's why you need the function 'callable' immediately after you change the combobox value from the button class.  Note that you don't need the RefreshActiveView() command at all to refresh the combobox; simply calling the function triggers the internal 'update' mechanism on the combobox (if no additional logic entered, then use 'pass').  The use of RefreshActiveView() here was just a point of good housekeeping to also refresh the view.

- You can include, if you wish, your other business logic in the button class to actually clear all selected features in the map....but that is academic at this point, as I said you can add logic as needed.

Understand?  It's simple when you have a handle on it.  (okay, that pun was intended)

Enjoy,
Wayne


PS- By the way, you could even clear the list via the button with:  combobox.items = [], although that really doesn't have any practical value -- I think you'd want to reload the list using a different query, etc., if that makes sense.

View solution in original post

0 Kudos
5 Replies
T__WayneWhitley
Frequent Contributor
I have a workaround that doesn't use the editable property, but instead simply 'resets' any entered value in the combobox back to the last valid value (from the drop-down list of course).  This is my test combobox script, kept short and easy to read, follow, and implement - easily modified to work on a selected set of field values or whatever the case may be.  To keep things very simple, I'm only using some feature layers in my map's TOC.  Some print statements were left in, in case you wanted to 'watch' from ArcMap's Python window.
import arcpy
import pythonaddins
 
class ComboBoxClass1(object):
    """Implementation for testNonEditCombo_addin.combobox (ComboBox)"""
   
    def __init__(self):
        self.editable = True
        self.enabled = True
        # introducing global
        global staticVal
        self.newfunction()
        self.value = staticVal = self.items[0]
       
    def onSelChange(self, selection):
        # redefining global
        global staticVal
        self.value = staticVal = selection
        print 'selection: {0}'.format(selection)
 
    def onEditChange(self, text):
        # I toyed with this function but decided not to use it in this example.
        pass
 
    def onFocus(self, focused):
        # if any layers are added/removed from the TOC, the list is refreshed.
        if focused: self.newfunction()
 
    def onEnter(self):
        self.value = staticVal
        print 'self.refresh...so did the refresh function fire?'
        self.refresh()
       
    def refresh(self):
        arcpy.RefreshActiveView()
        print 'refreshed...'
 
    def newfunction(self):
        self.mxd = arcpy.mapping.MapDocument('current')
        self.items = [lyr.name for lyr in arcpy.mapping.ListLayers(self.mxd)]


Let me know if you have further questions.

Wayne
0 Kudos
KatieGaut1
New Contributor III
Hi Wayne,
    Thanks so much for your response.   I suppose I should elaborate a bit more.  I have an add in with a few comboboxes and an "Unselect" button.  The comboboxes run queries on the data and the button clears the selections.

     I need the "Unselect" button to clear the comboboxes of their entries.  I've tried both of these options:

1)  Self.Editable=False, then the selection in the comboboxes disappear when the user selects something.  That's what I posted this question in regards to.

2)  Self.Editable=True, then the selection remains visible, but I can't get it to clear when the "Unselect" button is clicked, even when the selection is cleared.  (Code below)

    So, edit=true, can't get the unselect to clear the combobox, edit = false, the selection in the combobox automatically disappears.  Frustrating, huh?  Any other thoughts?

class ButtonUnselect(object):
    """Implementation for Walla_Walla_QueryTool_addin.button (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        self.mxd = arcpy.mapping.MapDocument('current')
        lyr = arcpy.mapping.ListLayers(self.mxd, "PODs")[0]
        lyr2 = arcpy.mapping.ListLayers(self.mxd, "POUs")[0]
        lyr3 = arcpy.mapping.ListLayers(self.mxd, "Management_Points")[0]
        arcpy.SelectLayerByAttribute_management(lyr, "CLEAR_SELECTION")
        arcpy.SelectLayerByAttribute_management(lyr2, "CLEAR_SELECTION")
        arcpy.SelectLayerByAttribute_management(lyr3, "CLEAR_SELECTION")
        df = arcpy.mapping.ListDataFrames(self.mxd)[0]
        ext = lyr2.getExtent()
        df.extent = ext
        combobox_2.__init__
        ComboBoxPriorityDateRange.__init__
        combobox_5.__init__
0 Kudos
T__WayneWhitley
Frequent Contributor
I'm sorry to say, although you may already realize this, what you state as your 'business logic' and your implementation attempt to accomplish said logic are not quite coherent.  I suppose we can conclude you're still in the right place, as we are all still learning.

Let me warp this conversation back to what I surmise is 'the center'.  What you say you want to do is quite easy to accomplish - but I don't want to delve too far into the details of your 'other' business logic because I think it can be hinged or added to the logic 'framework', if you will, that I show here.  Besides, it is simpler just to add to what code sample (involving a single combobox) I've already posted above - I'll repeat the code below and add-in (no pun intended) the button code....and offer a few pointers further below.
import arcpy import pythonaddins  class ButtonClass7(object):     """Implementation for testNonEditCombo_addin.button (Button)"""     def __init__(self):         self.enabled = True         self.checked = False     def onClick(self):         combobox.value = ''         combobox.refresh()  class ComboBoxClass1(object):     """Implementation for testNonEditCombo_addin.combobox (ComboBox)"""          def __init__(self):         self.editable = True         self.enabled = True         # introducing global         global staticVal         self.newfunction()         self.value = staticVal = self.items[0]              def onSelChange(self, selection):         # redefining global         global staticVal         self.value = staticVal = selection         print 'selection: {0}'.format(selection)      def onEditChange(self, text):         pass      def onFocus(self, focused):         if focused: self.newfunction()      def onEnter(self):         self.value = staticVal         print 'self.refresh...so did the refresh function fire?'         self.refresh()              def refresh(self):         arcpy.RefreshActiveView()         print 'refreshed...'      def newfunction(self):         self.mxd = arcpy.mapping.MapDocument('current')         self.items = [lyr.name for lyr in arcpy.mapping.ListLayers(self.mxd)]


So, just to add a few small explanations, here you go:

- My logic doesn't really do anything but load existing layers from the map into the combobox 'list'; add your own logic to select and zoom, whatever you want, where applicable.

- The only thing modified in the added button is the 'onClick' where you said you simply wanted to 'clear the selection' in the combobox.  See my reference to the combobox, "testNonEditCombo_addin.combobox"?  The object reference to that class is simply 'combobox'.

- Then, using that obj ref, the command to clear the box to essentially a blank value is:
combobox.value = ''

- However, you need to refresh the combobox to show it, hence the next line which calls the already existing refresh function:
combobox.refresh()

- Notice that function in the combox class simply calls the familiar refresh active view command, arcpy.RefreshActiveView()... it is the timing of the refresh execution you're interested in, so that's why you need the function 'callable' immediately after you change the combobox value from the button class.  Note that you don't need the RefreshActiveView() command at all to refresh the combobox; simply calling the function triggers the internal 'update' mechanism on the combobox (if no additional logic entered, then use 'pass').  The use of RefreshActiveView() here was just a point of good housekeeping to also refresh the view.

- You can include, if you wish, your other business logic in the button class to actually clear all selected features in the map....but that is academic at this point, as I said you can add logic as needed.

Understand?  It's simple when you have a handle on it.  (okay, that pun was intended)

Enjoy,
Wayne


PS- By the way, you could even clear the list via the button with:  combobox.items = [], although that really doesn't have any practical value -- I think you'd want to reload the list using a different query, etc., if that makes sense.
0 Kudos
KatieGaut1
New Contributor III
Thanks Wayne.  I knew it was likely something simple...and it was.  I apologize for the apparently "incoherent" logic.  I just started writing code literally a month ago.  It's a steep learning curve.

- Katie
0 Kudos
T__WayneWhitley
Frequent Contributor
It's okay...I'm learning too and have to admit, you posed a good challenge.  Point to you for hanging in there!

No need to apologize - next time, please post all of your relevant code...no 'subset' that may confuse matters.

Thanks,
Wayne
0 Kudos