2

I have created a Python Add-in for ArcMap 10.4 that involves a wxPython UI to display upon a click on a map. The UI is populated with default values as well as a combobox displaying the layers on the map. It works perfectly the first time it is run, but the second time, it does not update to show the current layers and displays the last values entered rather than the default values I have specified.

I believe this to be because self.Destroy does not work with wxPython in ArcMap. I had previously worked around this by using self.Show(False), like an example I found here. However, I believe that when being run more than once, the script is only changing the visibility of the UI back to 'True' and not actually opening a new UI.

So, is there any alternative to using self.Destroy() to get rid of my UI?

Here is an example of my script:

import arcpy
import pythonaddins
import wx

class ToolClass2(object):
"""Implementation for DesignTool.tool (Tool)"""
    dlg= None   
    def __init__(self):       
        self.enabled = True
        self.shape = "NONE" # Can set to "Line", "Circle" or "Rectangle" for interactive shape drawing and to activate the onLine/Polygon/Circle event sinks.
        self.cursor=3 #set cursor to crosshair        
    def onMouseDownMap(self, x, y, button, shift):
        global laylist
        laylist=[]
        mxd=arcpy.mapping.MapDocument("CURRENT")
        for lyr in arcpy.mapping.ListLayers(mxd):
           laylist.append(lyr.name)
        del mxd
        if self.dlg is None:  
            self.dlg = TestDialog()  
        else:  
            self.dlg.Show(True)  
        return  

class TestDialog(wx.Frame):  
    def __init__(self):  
        wxStyle = wx.CAPTION | wx.RESIZE_BORDER | wx.MINIMIZE_BOX |wx.CLOSE_BOX | wx.SYSTEM_MENU | wx.CB_DROPDOWN 
        wx.Frame.__init__(self, None, -1, "Design Form", style=wxStyle, size=(330, 370))  
        self.SetMaxSize((330, 370))  
        self.SetMinSize((330, 370))  
        self.Bind(wx.EVT_CLOSE, self.OnClose)  
        panel = wx.Panel(self, -1)  
        wx.StaticText(panel, -1, "Choose Layer:", pos=(8,64))  
        self.LayerCombo = wx.ComboBox(panel, -1, value=laylist[1], pos=(180, 64), size=(120,21), choices=laylist)
        self.Bind(wx.EVT_BUTTON, self.OnSet, id=self.btnSet.GetId())  
        self.Show(True)  

    def OnClose(self, event):  
        self.Show(False) # self.Destroy() doesn't work          

    def OnSet(self, event):  
        Layerpath= str(self.LayerCombo.GetValue())  
        self.Show(False)

app = wx.PySimpleApp()  
app.MainLoop()  
1

I think you are correct regarding the script only changing the UI. This is because the dlg attribute of your ToolClass2 is always pointing to the same instance of the TestDialog UI class.

When you first run the tool, the TestDialog instance is created and your Add-in works as intended. Next time, since self.dlg is not None, your else clause just shows the current instance and values.

One suggestion to fix this would be to ensure a new instance of TestDialog is created each time:

def onMouseDownMap(self, x, y, button, shift):
    global laylist
    laylist=[]
    mxd=arcpy.mapping.MapDocument("CURRENT")
    for lyr in arcpy.mapping.ListLayers(mxd):
       laylist.append(lyr.name)
    del mxd
    self.dlg = TestDialog() # always create a new instance

Or you could stick with this one instance of TestDialog but make sure that when you close it you also reset the values:

def OnClose(self, event):  
    self.Show(False) # self.Destroy() doesn't work
    # Now reset your values

Hope this helps.

  • I JUST realized this and made the changes you suggested in the first example. Works perfectly! – Ashton Jul 22 '16 at 13:56

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.