1

I have a directory change monitor python script which monitors any changes happened in a directory, I want to trigger Arcmap auto refreshing whenever a change has been detected (eg. a new line added to a file). I tried to launch the monitor program within arcmap python command window using execfile("myprogram.py"). The problem I encountered is that once the script starts to monitor and auto-refresh, the arcmap main window was locked and frozen, no way to stop it except shutting down the arcmap, although I can see the auto-refresh happened whenever there is a change. Is there a way to run the monitor script in a separate process or background without locking or freezing the main window? Here is my monitor script which is borrowed from Tim Golden,

    import os
    import win32file
    import win32con
    import arcpy

    # Search for the new data
    ACTION = {
       1: "Created",
       2: "Deleted",
       3: "Updated",
       4: "Renamed from something",
       5: "Renamed to something"
    }


    FILE_LIST_DIRECTORY = 0X0001
    path_to_watch = "C:\Directory"

    hDir = win32file.CreateFile(
          path_to_watch,
         FILE_LIST_DIRECTORY,
         win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE |   win32con.FILE_SHARE_DELETE,
         None,
          win32con.OPEN_EXISTING,
          win32con.FILE_FLAG_BACKUP_SEMANTICS,
          None
     )


     while 1:
        results = win32file.ReadDirectoryChangesW(
            hDir,
            1024,
            True,
            win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
            win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
            win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
            win32con.FILE_NOTIFY_CHANGE_SIZE |
            win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
            win32con.FILE_NOTIFY_CHANGE_SECURITY,
            None,
            None
         )

    for action, file in results:
        full_filename = os.path.join(path_to_watch, file)
        print full_filename, ACTION.get(action, "Unknown")
        arcpy.RefreshActiveView()
3
  • The problem is that they operate on different threads. ArcGis is still a single thread application and trying to influence it outside its thread is going to cause a problem. The best you could hope for is a timer event from ArcMap to pick up a boolean set by the Contents Changed event... to my knowledge python doesn't have delegate functions. If you're any good with C# I have a working example of something fairly similar - using Dynamic Display. Jul 14, 2015 at 3:14
  • Is it possible to trigger the event outside arcgis? I have C# experience, would like to see your example, Thanks.
    – zheng
    Jul 14, 2015 at 3:28
  • You can delegate it. I'll dig up the important parts of the code. I think though the best way around it is to use the Dynamic Display which comes with an OnTimerElapsed event (customizable, default 500ms I think) Jul 14, 2015 at 3:37

1 Answer 1

1

Here is the absolute nuts and bolts of the method:

IDynamicMap gDynamicMap;
IDynamicDisplay gDynamicDisplay;
FileSystemWatcher eLogWatcher;
bool gLOGchanged = false;

protected override void OnClick()
{
    IMap pMap = ArcMap.Document.FocusMap;
    gDynamicMap = (IDynamicMap)pMap;
    if (!gDynamicMap.DynamicMapEnabled) gDynamicMap.DynamicMapEnabled = true;
    gDynamicMap.DynamicDrawRate = (int)RefreshRate.Value; // set your refresh rate here
    
    // wire dynamic events
    ((IDynamicMapEvents_Event)gDynamicMap).DynamicMapFinished += new IDynamicMapEvents_DynamicMapFinishedEventHandler(OnTimerElapsed);
    ((IDynamicMapEvents_Event)gDynamicMap).AfterDynamicDraw += new IDynamicMapEvents_AfterDynamicDrawEventHandler(OnAfterDynamicDraw);
    
    // start the watcher
    eLogWatcher = new FileSystemWatcher();
    eSnavWatcher.Path = BaseFolderPath.Text + "\\pos";
    eSnavWatcher.Filter = "*.log"; // set this or you'll get events for every file that changes
    eSnavWatcher.NotifyFilter = NotifyFilters.LastWrite; // this too, limit the events
    eSnavWatcher.Changed += new FileSystemEventHandler(eSnavWatcher_Changed);
    eSnavWatcher.EnableRaisingEvents = true;
}
private void OnTimerElapsed(IDisplay Display, IDynamicDisplay dynamicDisplay)
{
    # do some processing in here, the map is already being refreshed
    # it is safe to do nothing here if !gLOGchanged - nothing to do.
    if (gLOGchanged)
    {
        # do your reading here
        gLOGchanged = false; // reset!
    }
}

void OnAfterDynamicDraw(esriDynamicMapDrawPhase DynamicMapDrawPhase, IDisplay Display, IDynamicDisplay dynamicDisplay)
{
    # draw graphics to the screen here
}

void eSnavWatcher_Changed(object sender, FileSystemEventArgs e)
{
    gLOGchanged = true;
}

The key here is the DynamicMap and DynamicDisplay which fires every interval continuously. In order to draw graphics you need to use DynamicSymbols (not standard symbols).

Using a FileSystemWatcher I set a boolean if a file is changed and then with the regular refresh detect that boolean indicating the file has changed. Note: with buffering the file may not change when you think it does, the FileSystemWatcher responds only when the file on disc has changed.

This code comes from a working tool that plots the course of a vehicle in real time (or near enough to) on a notebook to tell if the vehicle is going off course and correct before the data captured is invalid.

7
  • This solution can be made as an arc toolbox or a standalone exe? Thank you so much for the code, I will give a try on this solution!
    – zheng
    Jul 14, 2015 at 14:19
  • It is best to create as an add-in (.esriaddin) help.arcgis.com/en/sdk/10.0/arcobjects_net/conceptualhelp/… Install Visual Studio (I have 2010) - see desktop.arcgis.com/en/desktop/latest/get-started/… (Express 2012 works) then install the SDK from your ArcGis install media. Jul 14, 2015 at 21:38
  • My organization banned out the SDK and add-in development, so I have to wait for my license of SDK to implement the work.
    – zheng
    Jul 16, 2015 at 20:11
  • That's lamentable Zheng, you can use ArcObjects in python but you still need the SDK installed... btw. what reason for not allowing it? Visual Studio Express is free (registration required) and there is no additional charge for the SDK (it's on your install media but it wont ask unless the installer detects a suitable VS - see gis.stackexchange.com/questions/62720/…) Jul 16, 2015 at 21:46
  • I have visual studio 2012 installed, but lack of ArcObject SDK. Is there free version of ArcObject? Our arcgis installation follows a specific workflow, not the normal media installation, there is no Arcobject option there. Guess its for security reason.
    – zheng
    Jul 16, 2015 at 22:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.