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?
-
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– Nathanus2011年04月15日 17:49:22 +00:00Commented Apr 15, 2011 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– Luke2011年04月15日 19:26:53 +00:00Commented Apr 15, 2011 at 19:26
1 Answer 1
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.
-
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– Nathan W2011年04月15日 14:39:03 +00:00Commented Apr 15, 2011 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– Nathan W2011年04月15日 14:44:40 +00:00Commented Apr 15, 2011 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– Luke2011年04月15日 16:08:01 +00:00Commented Apr 15, 2011 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– Nathanus2011年04月15日 17:46:44 +00:00Commented Apr 15, 2011 at 17:46
-
in most cases the python location is stored in the environment path (for windows machines) as well.Luke– Luke2013年05月11日 15:46:29 +00:00Commented May 11, 2013 at 15:46