class ButtonClass1(object): """Implementation for UndoRedo_addin.button (Button)""" def __init__(self): self.enabled = True self.checked = False def onClick(self): edit = arcpy.da.Editor(r'C:\addin\projects\EditSession\f.gdb') edit.startEditing() edit.startOperation() arcpy.DeleteFeatures_management("fishparcels_line") arcpy.RefreshActiveView() edit.stopOperation() edit.stopEditing(True) arcpy.RefreshActiveView()
Thanks for the reply. Sorry I didn't notice it sooner.
My question was more about getting a Python add-in to integrate with ArcMap's undo/redo stack like VBA. Your example works, but does not address 2 things I'm interested in:
1) Accessing the workspace ArcMap is currently editing
2) Setting a name for the operation, so ArcMap's undo button can say what would be undone.
It does not look like Python add-in's can do this.
Thanks,
Mark
No need to mess around with ArcObjects and .NET. You can create your own edit stack. You can simply set a global variable that tracks the edits and is then accessible to other buttons.
For example, depending on the complexity of the edits performed by your add-in, you could have a global list to which you append information about the edits.
Here's an example of a simple edit button (it just buffers the selected features) with undo and redo buttons. Note that these are not the built-in undo/redo buttons, but Add-In buttons that you create. The edits here will be in a separate stack from the built-in edits.
import arcpy
import pythonaddins
MXD = arcpy.mapping.MapDocument('CURRENT')
FN_SHAPE = 'SHAPE@'
# Global variables that will store the edit histories forward and backward
undo_stack = list()
redo_stack = list()
class MakeEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
# Get the selected layer in the table of contents
lyr = pythonaddins.GetSelectedTOCLayerOrDataFrame()
# Get a count of selected features in the selected layer
fid_set = arcpy.Describe(lyr).FIDSet
if fid_set == '':
count = 0
else:
count = len(fid_set.split(';'))
# If at least one feature is selected
if count > 0:
# Enable global modification of the undo_stack
global undo_stack
# Get the name of the layer's OID field
fn_oid = arcpy.Describe(lyr).OIDFieldName
with arcpy.da.UpdateCursor(lyr, [fn_oid, FN_SHAPE]) as cur:
for row in cur:
# Add the relevant details to the editing stack
undo_stack.append((lyr, fn_oid, row[0], row[1]))
# An arbitrary example edit
row[1] = row[1].buffer(500)
cur.updateRow(row)
arcpy.RefreshActiveView()
class RedoEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
global undo_stack
global redo_stack
if len(redo_stack) > 0:
# Get the last item in the edit stack
edit = redo_stack.pop()
# Clear any existing selection on the layer, or else the cursor may
# not hit the necessary feature
arcpy.SelectLayerByAttribute_management(edit[0], 'CLEAR_SELECTION')
# A where clause to select the most recently edited feature
wc = '{} = {}'.format(edit[1], edit[2])
with arcpy.da.UpdateCursor(edit[0], FN_SHAPE, wc) as cur:
for row in cur:
# Update the undo edit stack
edit_out = list(edit[:-1])
edit_out.append(row[0])
undo_stack.append(edit_out)
# Apply the edit
row[0] = edit[3]
cur.updateRow(row)
break
arcpy.RefreshActiveView()
class UndoEdits(object):
def __init__(self):
self.enabled = True
self.checked = False
def onClick(self):
global undo_stack
global redo_stack
if len(undo_stack) > 0:
edit = undo_stack.pop()
arcpy.SelectLayerByAttribute_management(edit[0], 'CLEAR_SELECTION')
wc = '{} = {}'.format(edit[1], edit[2])
with arcpy.da.UpdateCursor(edit[0], FN_SHAPE, wc) as cur:
for row in cur:
edit_out = list(edit[:-1])
edit_out.append(row[0])
redo_stack.append(edit_out)
row[0] = edit[3]
cur.updateRow(row)
break
arcpy.RefreshActiveView()
return