Take the 2-minute tour ×
Geographic Information Systems Stack Exchange is a question and answer site for cartographers, geographers and GIS professionals. It's 100% free, no registration required.

Coming from the same background as the original poster in this thread, I wonder if anyone has had any success creating an Arc10 Add-In using IronPython.

I have been able to access ArcObjects via IronPython using the info in the linked thread, assorted blog postings, and a few posts on the ESRI forums. These neophyte attempts have all been run from the command line and I would to be able to gain access through either a toolbar or a button.

One thought that I had was to create the add-in using the .Net 3.5 template, add a python file, and then call a function in the python file from the button's C# file. It appears though that add-ins are not yet supported in .Net4?

Here is the code from the .cs file which controls button functionality.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

//I need to then add references to IronPython
using IronPython;
using IronPython.Hosting;
using Microsoft.Scripting;
using Microsoft.Scripting.Hosting;

namespace PyButtonTest
{
    public class ZoomToLayer : ESRI.ArcGIS.Desktop.AddIns.Button
    {
        public ZoomToLayer()
        {
        }

        protected override void OnClick()
        {
            var ipy = Python.CreateRuntime();
            dynamic test = ipy.UseFile("ZoomToLayer.py");
            test.ZoomToActiveLayerInTOC(); //Call this function in the py file

            ArcMap.Application.CurrentTool = null;
        }
        protected override void OnUpdate()
        {
            Enabled = ArcMap.Application != null;
        }
    }

}

As far as I can tell the Add-in format takes care of getting the application hook. I should then be able to, in the python file, after referencing and importing all of the necessary libraries get the map document with (I think?)

mxDoc = ArcMapUI.IMxDocument.ActiveView

From here I am stumped. Google has not turned up anything helpful. Has anyone else tried this? Got something to work? Do I need to wait until add-ins are supported in .Net4 to go this route?

share|improve this question
    
ArcMap doesn't support .Net4 yet? ESRI is always so behind. Unfortunately, I haven't had the chance to even begin exploring ArcObjects yet (suddenly my GIS Analyst title extends to Web Development), but I wish you the best of luck with this! Although it would help if my manager didn't think that non-standard libraries were bad hoodoo. –  Nathanus Apr 15 '11 at 17:49
    
If you're trying to run a Zoom to Selected Layer there was an example of how to do that in DOTNET for the 9.3 platform up on the resource center for a while. I have a version of it if you are interested. If that is your end goal with running python from a button. –  Luke Apr 15 '11 at 19:26

1 Answer 1

up vote 2 down vote accepted

So I'm hoping this helps. I was having an issue with the 3.5 framework a few weeks back, to the point that I couldn't build and populate a new geodatabase using straight up ArcObjects within my Add-in. However I could do all of that work from my python prototype. So what I ended up doing was building a wrapper method that just called my python directly (no iron python needed). I also have a method that tracks down the python executable path (which if memory serves, iron python needs anyway):

    public void RunPython(String pythonpath, String filename)
    {
        Process p = new Process();
        p.StartInfo.FileName = pythonpath;
        p.StartInfo.Arguments = "C:\\Users\\Luke\\workspace\\EclipseWorkspace\\GCWWPythonSVN\\src\\EditorUtilities\\SurveyLoader.py " //
            + '"' + filename + '"';
        p.StartInfo.UseShellExecute = true;
        p.StartInfo.CreateNoWindow = false;
        p.Start();

        p.WaitForExit();
    }

    public String FindPythonPath()
    {
        String pythondirectory = "";
        DriveInfo[] allDrives = DriveInfo.GetDrives();
        foreach (DriveInfo dirInfo in allDrives)
        {
            if (dirInfo.IsReady)
            {
                String[] driveDir = Directory.GetDirectories(dirInfo.Name);
                foreach (String dir in driveDir)
                {
                    if (dir.Contains("Python"))
                    {
                        String[] directoryInfo = Directory.GetFiles(dir);
                        if (directoryInfo.Length == 0)
                        {
                            String[] pythonFolder = Directory.GetDirectories(dir);
                            foreach (String pyDir in pythonFolder)
                            {
                                String[] pyDirFiles = Directory.GetFiles(pyDir);
                                foreach (String file in pyDirFiles)
                                {
                                    if (file.Contains("python.exe"))
                                    {
                                        pythondirectory = file;
                                        break;
                                    }
                                }
                            }
                        }
                        else
                        {
                            String[] fileFolder = Directory.GetFiles(dir);
                            foreach (String pyfile in directoryInfo)
                            {
                                if (pyfile.Contains("python.exe"))
                                {
                                    pythondirectory = pyfile;
                                    break;
                                }
                            }
                        }
                    }
                }
            }
            if (!pythondirectory.Equals(""))
            {
                break;
            }
        }
        return pythondirectory;
    }

In my case I'm passing in the csv file that I'm parsing through with the python code. So you with the Add -in (or a COM hook for that matter), you should be able to pass the map document. My application ends up firing a python command line window from my click event, but I'm guessing that if you're firing off a python app with IP you're expecting the PVM to run anyway.

p.StartInfo.Arguments = "C:\Users\Luke\workspace\EclipseWorkspace\GCWWPythonSVN\src\EditorUtilities\SurveyLoader.py " // + '"' + filename + '"';

Hope this helps.

share|improve this answer
    
All those nested if statements really scare me o_0 I hope this is not production code. Tip: You could exit early with some of those if statements to avoid the massive nesting. –  Nathan W Apr 15 '11 at 14:39
    
also I'm not sure just brute force searching for python would be very good. I'm pretty sure its location is stored in the registry. –  Nathan W Apr 15 '11 at 14:44
    
the brute force bit is productional with another application, but it's due for a refactor and upgrade (that method works perfectly oddly enough) -- I'm having an issue with my synchronization component. and I personally HATE even thinking about mucking around with the registry. EVER. –  Luke Apr 15 '11 at 16:08
    
The if nesting is numerous, but I find it pretty darn readable, regardless. "Optimized" code is usually what trips me up. Ah, the grace of ignorance. :) –  Nathanus Apr 15 '11 at 17:46
    
in most cases the python location is stored in the environment path (for windows machines) as well. –  Luke May 11 '13 at 15:46

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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