I'm writing some code to create a toolbar that edits a map in ArcMap and I'm having some issues with getting variable values from other functions inside other classes that I'm using.
All the functions are predefined so I can't change the int
arguments or the code will throw an error. I checked the dir()
and none of the variables I define using self
are in the functions. I don't think I've made a syntax error and the code inside the other classes works correctly.
Here is my code:
import arcpy
import math
import pythonaddins
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
class squareFeetInput(object):
"""Implementation for leetScripts_addin.combobox (ComboBox)"""
def __init__(self):
self.editable = True
self.enabled = True
#self.dropdownWidth = 'WWWWWW'
self.width = 'WWWWWW'
def onEditChange(self, text):
squareFeet = text
#this is the other variable I defined that I need to use later
self.buffDist = (math.sqrt(float(squareFeet))/2)
print "Square size: %r ft^2 Buffer Distance: %r ft^2" % (squareFeet,self.buffDist)
print "self.buffdist is a %r type" % self.buffDist
return self.buffDist
pass
class buildingTool(object):
"""Implementation for leetScripts_addin.button (Button)"""
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
print "building tool is executing"
#shows im_self, but no x or y
print "%r" % dir(findingCoordinates.onMouseDownMap)
# Get arguments:
# Input point feature class
# Output polygon feature class
# Buffer distance
# Boolean type: Maintain fields and field values of the input in the output
#This is where the problem is. I can't get these values from the previous functions.
inPoints = (findingCoordinates.onMouseDownMap.x,findingCoordinates.onMouseDownMap.y)
outPolys = "U:\JackBuildingFootprints.gdb\BuildingFootprintsCopy"
bufDist = squareFeetInput.buffDist
keepFields = true
# Prepare the output based on whether field and field values are desired in the output
#
if keepFields:
# Create empty output polygon feature class that includes fields of the input
#
arcpy.CreateFeatureClass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
inPoints, "", "", inPoints)
# Create a short list of fields to ignore when moving fields values from
# input to output
#
ignoreFields = []
# Use Describe properties to identify the shapeFieldName and OIDFieldName
#
desc = arcpy.Describe(inPoints)
ignoreFields.append(desc.shapeFieldName)
ignoreFields.append(desc.OIDFieldName)
# Create a list of fields to use when moving field values from input to output
#
fields = arcpy.ListFields(inPoints)
fieldList = []
for field in fields:
if field.name not in ignoreFields:
fieldList.append(field.name)
else:
# Create empty output polygon feature class without fields of the input
#
arcpy.CreateFeatureclass(os.path.dirname(outPolys), os.path.basename(outPolys), "POLYGON",
"", "", "", inPoints)
# Open searchcursor
#
inRows = arcpy.SearchCursor(inPoints)
# Open insertcursor
#
outRows = arcpy.InsertCursor(outPolys)
# Create point and array objects
#
pntObj = arcpy.Point()
arrayObj = arcpy.Array()
for inRow in inRows: # One output feature for each input point feature
inShape = inRow.shape
pnt = inShape.getPart(0)
# Need 5 vertices for square buffer: upper right, upper left, lower left,
# lower right, upper right. Add and subtract distance from coordinates of
# input point as appropriate.
for vertex in [0,1,2,3,4]:
pntObj.ID = vertex
if vertex in [0,3,4]:
pntObj.X = pnt.X + bufDist
else:
pntObj.X = pnt.X - bufDist
if vertex in [0,1,5]:
pntObj.Y = pnt.Y + bufDist
else:
pntObj.Y = pnt.Y - bufDist
arrayObj.add(pntObj)
# Create new row for output feature
#
feat = outRows.newRow()
# Shift attributes from input to output
#
if keepFields == "true":
for fieldName in fieldList:
feat.setValue(fieldName, inRow.getValue(fieldName))
# Assign array of points to output feature
#
feat.shape = arrayObj
# Insert the feature
#
outRows.insertRow(feat)
# Clear array of points
#
arrayObj.removeAll()
# Delete inputcursor
#
del outRows
pass
What am I doing wrong? Is this one of the rare occasions where I should use a global variable? Why is the directory not showing the variables I defined using self
?
Edit:
I made this post a while ago and I just wanted to clear some things up now that I know more.
First:
This is code that is designed to be use with python_add_in. Python add in creates a toolbar based on some parameters you give it when you set it up, and whatever python code you put into a template it makes as a result of those parameters. That essentially means that all of the classes in the script above are events that occur when buttons and other toolbar objects are clicked or used in the toolbar.
Second:
The solution to this problem actually isn't in the accepted answer, my bad.
The root cause of the problem is that I was using class names that I declared in my script, findingCoordinates
for example. python_add_in doesn't recognize these class names as the names of the classes it expects to receive based on the template you fill out before you start coding.
With that in mind, the issue was that I was trying to call classes that just didn't exist as far as python_add_in was concerned. The solution is to just go ahead and use the class names python_add_in tool expects you to use. These names are in the docstring located below the class definition so where I have findingCoordinates
I should have Tool
.
I hope this helps.
self
refers to an instance of the class that you've defined, so to access those values, you need to create an instance of the class, call the method, and then access the values from the instance.
For example:
In [9]: %paste
class findingCoordinates(object):
"""Implementation for leetScripts_addin.tool (Tool)"""
def __init__(self):
self.enabled = True
self.shape = "NONE"
def onMouseDownMap(self, x, y, button, shift):
print "onMouseDowMap executing"
#this is where I declared the first two variables using self
self.x = x
self.y = y
print "Selected point is at %r, %r" % (self.x, self.y)
pass
## -- End pasted text --
In [10]: f = findingCoordinates()
In [11]: f.onMouseDownMap(x=1, y=2, button="button", shift="shift")
onMouseDowMap executing
Selected point is at 1, 2
In [12]: f.x
Out[12]: 1
In [13]: f.y
Out[13]: 2
EDIT: It seems like you've had some confusion about scoping/namespaces as well. There's no x
or y
defined globally; they just exist within the class instances. That will also allow you to have separate x
and y
values for different instances of the class.
In [14]: x
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-14-401b30e3b8b5> in <module>()
----> 1 x
NameError: name 'x' is not defined
In [15]: y
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-15-009520053b00> in <module>()
----> 1 y
NameError: name 'y' is not defined
In [16]: g = findingCoordinates()
In [17]: g.onMouseDownMap(100,200,0,0)
onMouseDowMap executing
Selected point is at 100, 200
In [18]: f.x, f.y
Out[18]: (1, 2)
In [19]: g.x, g.y
Out[19]: (100, 200)