I'm having a strange issue with creating Python Add-Ins with comboboxes. I have a pretty simple Python Add-In in which the user can draw a rectangle to select some lines from a specific layer (layer name grabbed from combobox layer list) . By using comtypes and ArcObjects, it will place a text element showing the quadrant bearing of the line at its midpoint in DMS format. However, I am having an issue where the combox.value attribute is getting deleted somehow. This has happened before, and to remedy it I had to delete the addin_assistant folder, re-download it and build the Add-In again from scratch. This fix did not work this time. There is nothing in my code that would delete the value and my code fails here:
Has anyone else experienced this? The problem could be a bad install. I am running 10.2 on a VM. This smells like a corrupted DLL somewhere to me. Here is my full code:
import arcpy
import pythonaddins
import math
import sys
sys.path.append(r'\\Arcserver1\GIS\_Resources\ESRI\Python\BMI_Library')
import arcobjects #custom module
from arcobjects import elements
def makePolyFromExtent(ext, sr):
'''makes an arcpy polygon object from an input extent object.
Returns a polygon geometry object.'''
array = arcpy.Array()
array.add(ext.lowerLeft)
array.add(ext.lowerRight)
array.add(ext.upperRight)
array.add(ext.upperLeft)
array.add(ext.lowerLeft)
return arcpy.Polygon(array, sr)
def get_angle(xy1, xy2):
"""Calculate azimuth angle from two points. (Zero is north.)"""
# function courtesy of Curtis Price
try:
# ArcPy point objects
x1, y1, x2, y2 = xy1.X, xy1.Y, xy2.X, xy2.Y
except:
# xy strings, e.g. "0 0"
x1, y1 = [float(x) for x in xy1.split()]
x2, y2 = [float(x) for x in xy2.split()]
dx, dy = (x2 - x1, y2 - y1)
return 90 - math.degrees(math.atan2(dy, dx))
def quadrant_bearing(line):
"""returns quadrant bearing in DMS"""
deg = '\xb0'
pt1 = line.firstPoint
pt2 = line.lastPoint
angle = abs(get_angle(pt1, pt2) - 180)
d = int(math.floor(angle))
m_float = (angle - d) * 60.0
m = int(m_float)
s = (m_float - m) * 60
return '{0}{1} {2}\' {3:.2f}"'.format(d,deg,m,s)
def midpoint(point_a, point_b):#, sr):
x1 = point_a.X
y1 = point_a.Y
x2 = point_b.X
y2 = point_b.Y
# Find midpoint
x = (x1 + x2) / 2.0
y = (y1 + y2) / 2.0
return (x, y)
class ComboBoxClass1(object):
"""Implementation for LineAngles_addin.combobox (ComboBox)"""
def __init__(self):
self.editable = True
self.enabled = True
self.dropdownWidth = 'W' * 12
self.width = 'W' * 12
def onFocus(self, focused):
if focused:
mxd = arcpy.mapping.MapDocument('current')
df = mxd.activeDataFrame
lyrs = [l.name for l in arcpy.mapping.ListLayers(mxd, '*', df)
if not l.isBroken and l.supports('DATASOURCE')]
self.items = sorted(lyrs)
del mxd
class ToolClass3(object):
"""Implementation for LineAngles_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "Rectangle"
self.cursor = 3
def onRectangle(self, rectangle_geometry):
# get spatial reference
print dir(combobox)
layer = combobox.value
mxd = arcpy.mapping.MapDocument('current')
df = mxd.activeDataFrame
sr = df.spatialReference
# make polygon extent object
poly = makePolyFromExtent(rectangle_geometry, sr)
# get layer's data type
lyr = arcpy.mapping.ListLayers(mxd, layer)[0]
# arcobjects get current app (IApplication interface Pointer)
pApp = arcobjects.GetCurrentApp()
# get dms as text
with arcpy.da.SearchCursor(line, 'SHAPE@') as rows:
for row in rows:
dms = quadrant_bearing(row[0])
# add text element
x,y = midpoint(row[0].firstPoint, row[0].lastPoint) # to place text element at midpoint of line
elements.add_text(pApp, text=dms, name='dms', size=12, bold=True, x=x, y=y, view='data') # add text element to data view
pass