1

I am trying to create an "auto refresh" tool for ArcMap, to refresh the DataFrame. I believe version 10 had an add-on you could download for this purpose.. however we are running 10.1 at work and there is no such tool.

EDIT wxPython's timer should work, however using wx in arc is tricky. Here's what the code looks like currently:

import arcpy
import pythonaddins
import os
import sys
sMyPath = os.path.dirname(__file__)
sys.path.insert(0, sMyPath)

WATCHER = None

class WxExtensionClass(object):
    """Implementation for Refresher_addin.extension (Extension)"""
    _wxApp = None
    def __init__(self):
        # For performance considerations, please remove all unused methods in this class.
        self.enabled = True
    def startup(self):
        from wx import PySimpleApp
        self._wxApp = PySimpleApp()
        self._wxApp.MainLoop()
        global WATCHER
        WATCHER = watcherDialog()


class RefreshButton(object):
    """Implementation for Refresher_addin.button (Button)"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        if not WATCHER.timer.IsRunning():
            WATCHER.timer.Start(5000)
        else:
            WATCHER.timer.Stop()

class watcherDialog(wx.Frame):
    '''Frame subclass, just used as a timer event.'''
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "timer_event")
        #set up timer
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)

    def onTimer(self, event):
        localtime = time.asctime( time.localtime(time.time()) )
        print "Refresh at :", localtime
        arcpy.RefreshActiveView()

    app = wx.App(False)

You will notice the PySimpleApp stuff in there. I got that from the Cederholm's presentation. I am wondering if I am misunderstanding something though. Should I create an entirely separate addin for the extension? THEN, create my toolbar/bar addin with the code I need? I ask this because I don't see the PySimpleApp referenced in your code below, or any importing from wx in the startup override method either... which I thought was required/the point of all this. I do appreciate your help. Please let me know what you see in my code.

default_noob_network
  • 1,204
  • 3
  • 19
  • 39

2 Answers2

3

You can't do this the way you are trying, because time.sleep will block and lock up the entire application. Python addins in ArcGIS is pretty new stuff, and there's a lot of functionality that hasn't been implemented yet. One of these is some kind of update or timer event like you get in .NET and ArcObjects. You might think of using threading.Thread and threading.Event in a case like this, but nothing to do with threads will work in the Python addin environment. At least I can't get it to work. So what I've done in situations like this is use wxPython and the Timer class. The code below will work if the addin is set up correctly.

import time
import os, sys
import wx
import arcpy

mp = os.path.dirname(__file__)
sys.path.append(mp)

WATCHER = None

class LibLoader1(object):
    """Extension Implementation"""
    def __init__(self):
        self.enabled = True

    def startup(self):
        global WATCHER
        WATCHER = watcherDialog()

class ButtonClass5(object):
    """Button Implementation"""
    def __init__(self):
        self.enabled = True
        self.checked = False
    def onClick(self):
        if not WATCHER.timer.IsRunning():
            WATCHER.timer.Start(5000)
        else:
            WATCHER.timer.Stop()

class watcherDialog(wx.Frame):
    '''Frame subclass, just used as a timer event.'''
    def __init__(self):
        wx.Frame.__init__(self, None, -1, "timer_event")
        #set up timer
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onTimer, self.timer)

    def onTimer(self, event):
        localtime = time.asctime( time.localtime(time.time()) )
        print "Refresh at :", localtime
        arcpy.RefreshActiveView()

    app = wx.App(False)

Make an extension addin, with a toolbar and a button class. Override the startup method of the extension as shown above. That will create an instance of a Frame subclass with a timer. Then, whenever you click the button on the toolbar, the timer will toggle on or off. The Timer argument is in milliseconds, so the code as shown will refresh every 5 seconds.

You can read more about using wxPython in addins here. Pay particular attention to MCederholm's posts, like about the print statement not working.

EDIT

The code uses a startup method override of the addin extension class. This method is supposed to run when Arcmap starts, but it seems from your comments that this startup method is failing to run on startup. That's possible if you don't create your addin just right, but it works fine for me in my tests. If you continue to get "AttributeError: 'NoneType' object has no attribute 'timer'", then change the onClick method of your button class like so:

def onClick(self):

    if WATCHER is None:
        global WATCHER
        WATCHER = watcherDialog()

    if not WATCHER.timer.IsRunning():
        WATCHER.timer.Start(5000)
    else:
        WATCHER.timer.Stop()

The first 3 lines check to make sure that the WATCHER variable has been set to an instance of watcherDialog and is not still set to None. Don't know why your startup method is not running, but hopefully this will fix things for you.

MikeHunter
  • 4,144
  • 1
  • 19
  • 14
  • Awesome! The code you provided looks great.. thank you! What I have been struggling with is getting wx to import in the python window in ArcMap. Not sure if it has to do with my installation of wxPython. I've installed it specifically in the ArcGIS10.1\lib however, I always get an error while trying to import wx. I am about to watch Mark Cederholm's 2012 dev summit presentation that I got from the link you referenced. (see another question of mine: http://stackoverflow.com/questions/16184829/inconsistency-between-idle-pythonwin-during-module-imports) – default_noob_network May 12 '13 at 02:49
  • Also the error I am getting is: Runtime error Traceback (most recent call last): File "", line 1, in File "C:\Python27\ArcGIS10.1\lib\site-packages\wx-2.8-msw-unicode\wx\__init__.py", line 45, in from wx._core import * File "C:\Python27\ArcGIS10.1\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 4, in import _core_ ImportError: DLL load failed: %1 is not a valid Win32 application. – default_noob_network May 12 '13 at 02:50
  • Do you get this error when trying to import wx in the python window, or importing it in an addin extension with a startup method? You must follow Cederholm's instructions exactly or you will get all kinds of errors like this. Import wx in an extension with a startup method, and you should be on your way. – MikeHunter May 12 '13 at 03:12
  • OK - finally got the extension to show up in Arc, and the button seems to want to play nicely. I AM getting a traceback: line 29, in onClick if not WATCHER.timer.IsRunning(): AttributeError: 'NoneType' object has no attribute 'timer' – default_noob_network May 12 '13 at 07:31
  • You'll need to go to addin manager and load the addin. Then restart Arcmap. Do that once, and it should load automatically on that machine. – MikeHunter May 12 '13 at 10:57
  • And check the config.xml file in the addin. Under Extensions, you should have the "autoload" property set to "true" – MikeHunter May 12 '13 at 11:07
  • I checked the congig.xml file, it looks okay. The extension loads up okay in Arc and the addin is loaded in Arc OK as well. Now, my OOP chops are still in their infancy, but based on that AttributeError I am getting there seems to be an issue with 'WATCHER.timer' Can I ask you, what exactly is WATCHER doing? And why might I be getting an error saying it has no attribute 'timer' ? – default_noob_network May 12 '13 at 18:04
  • please check out my edit which includes my script in its current state. I can include the config.xml if needed as well. I did try your latest suggestion, I couldn't get that to work either. – default_noob_network May 13 '13 at 01:01
0

You can use either the RefreshTOC or RefreshActiveView Method. Just add a timer

Community
  • 1
  • 1
Rachel Gallen
  • 27,943
  • 21
  • 72
  • 81