通过ArcPy检查ArcMap是否处于编辑会话中?


11

我创建了一个Python加载项按钮,通过将一个要素类属性复制到另一个要素类来帮助加快我的同事的工作流程。它使用arcpy.UpdateCursor函数更新目标要素类中的一行。现在,无论编辑模式如何,都可以运行此按钮脚本。显然,当脚本在编辑会话中运行时,用户可以选择停止编辑而不保存更改,但是当脚本在编辑会话之外运行时,情况并非如此。

如果ArcMap当前不在编辑会话中,如何向脚本添加检查以停止脚本运行?

这关系到ArcMap 10和10.1


我还想与其他ArcMap用户进行核对,以验证在没有进行编辑会话的情况下,通常不允许对表进行更新。

那么该脚本如何在编辑会话之外运行?

该脚本还提出了另一个问题,即当我从列表更新第二要素类表时,ArcMap执行的看似偶然的选择顺序正好对我有用,但这又是一天了。

这是现在可以正常运行的脚本(没有任何10.1编辑器实现):

如何添加检查以确保用户处于编辑会话中?

def onClick(self):
    #Reference mxd
    mxd = arcpy.mapping.MapDocument("CURRENT")
    #Reference the main Data frame
    mm = arcpy.mapping.ListDataFrames(mxd, "MainMap")[0]
    #Reference the Water System Valve feature class
    waterValves = arcpy.mapping.ListLayers(mxd, "Water System Valve", mm)[0]
    #Reference the fire hydrant feature class
    fireHydrants = arcpy.mapping.ListLayers(mxd, "Water Hydrant", mm)[0]

    #Use the extent of the main DF to select all valves in the current view
    dfAsFeature = arcpy.Polygon(arcpy.Array([mm.extent.lowerLeft, mm.extent.lowerRight, mm.extent.upperRight, mm.extent.upperLeft]), mm.spatialReference)
    arcpy.SelectLayerByLocation_management(waterValves, "WITHIN", dfAsFeature,"", "NEW_SELECTION")

    arcpy.SelectLayerByAttribute_management(waterValves, "SUBSET_SELECTION", "LOCATIONID IS NULL")

    fields = ["LOCATIONID"]

    row, rows = None, None
    rows = arcpy.UpdateCursor(waterValves,fields)
    row = rows.next()
    valveList = []
    append = valveList.append

    #Loop through the valves table to update LocationID
    while row:
        builder = str(row.QSNO)+"-"+ str(row.VALVESEQNO)
        row.setValue("LOCATIONID", builder)
        append(builder)
        rows.updateRow(row)
        row = rows.next()

    del row, rows

    #New selection for fire hydrants
    arcpy.SelectLayerByLocation_management(fireHydrants, "WITHIN", dfAsFeature,"", "NEW_SELECTION")
    arcpy.SelectLayerByAttribute_management(fireHydrants, "SUBSET_SELECTION", "LOCATIONID IS NULL")

    row, rows = None, None
    rows = arcpy.UpdateCursor(fireHydrants,fields)
    row = rows.next()

    #Loop through fire hydrant table to update LocationID
    while row:
        for locID in valveList:
            construct = str(locID) + "-FH"
            #print construct
            row.setValue("LOCATIONID", construct)
            rows.updateRow(row)
            row = rows.next()

    del row, rows, valveList, mxd

数据访问模块编辑器似乎独立于标准编辑器运行。我欢迎任何其他有关主动编辑会话测试的想法。-Karl
KarlJr

您能否提供更多信息?是什么导致您对尚未探索该模块的那些人得出这个结论?
杰伊·劳拉

Answers:


6

这是基于这篇文章的通用函数。

也许这比ArcObjects解决方案要复杂得多,但是看起来麻烦程度要小得多!简单胜于复杂。除非不是这样。

用法示例:

if CheckEditSession(tbl):
    print("An edit session is currently open.")

码:

def CheckEditSession(lyr):
    """Check for an active edit session on an fc or table.
    Return True of edit session active, else False"""
    edit_session = True
    row1 = None
    try:
        # attempt to open two cursors on the input
        # this generates a RuntimeError if no edit session is active
        OID = arcpy.Describe(lyr).OIDFieldName
        with arcpy.da.UpdateCursor(lyr, OID) as rows:
            row = next(rows)
            with arcpy.da.UpdateCursor(lyr, OID) as rows2:
                row2 = next(rows2)
    except RuntimeError as e:
        if e.message == "workspace already in transaction mode":
            # this error means that no edit session is active
            edit_session = False
        else:
            # we have some other error going on, report it
            raise
    return edit_session

+1不错的概念,但是,OP 不在编辑会话中要停止,在编辑会话中要继续。您的答案似乎相反。不过,可能不会花很多时间来解决这个问题。
Midavalo

OP已经解决了他的问题,这篇文章只是为我们提供了更有用的功能。我修改了示例,以更清楚地了解该函数的使用方式。
柯蒂斯价格

4

我对此问题的解决方案是使用可用于Arcpy插件工具栏的扩展。我添加了一个扩展,用于监听编辑会话的开始或结束。首先,我将栏上的所有按钮都设置为:self.enable = False”,然后通过启动或停止编辑会话来启用或禁用这些按钮。

class Active_Edit_Session(object):
"""Implementation for NEZ_EDITS_addin.Listen_for_Edit_Session (Extension)"""
def __init__(self):
    self.enabled = True
def onStartEditing(self):
    button_3100.enabled=True    
def onStopEditing(self, save_changes):
    button_3100.enabled=False

class LFM_3100(object):
    """Implementation for LFM_3100.button_3100 (Button)"""
    def __init__(self):
        self.enabled = False
        self.checked = False
    def onClick(self):
        ......

这看起来是一个值得尝试的解决方案。谢谢
user18412 2013年

4

我发布了另一个答案,因为我已经学会了使用ArcObjects和Python一起检查ArcMap中编辑器状态的新方法。我的答案大量借鉴了Mark Cederholm所做的工作(如本文中所引用):如何从Python访问ArcObjects?,以及Matt Wilkie在其“ Snippits.py”文件中提供的代码示例。您将需要按照第一个答案中提供的说明下载并安装comtype,然后获取Snippets.py脚本的副本。我将在下面的脚本中发布基本功能的副本。

调用函数ArcMap_GetEditSessionStatus()时,它将检查ArcMap中编辑器的当前状态,并返回true或false。这使我可以检查用户是否准备使用我的工具,或者是否需要提示他们开始编辑会话。该方法的缺点是在ArcObjects可以在Python中使用之前需要安装comtypes,因此可能无法在多用户办公环境中共享需要此软件包的工具。以我有限的经验,我不确定如何将它们捆绑在一起,以便作为Esri Python工具插件轻松共享。有关如何执行此操作的建议将不胜感激。

#From the Snippits.py file created by Matt Wilkie
def NewObj(MyClass, MyInterface):
    """Creates a new comtypes POINTER object where\n\
    MyClass is the class to be instantiated,\n\
    MyInterface is the interface to be assigned"""
    from comtypes.client import CreateObject
    try:
        ptr = CreateObject(MyClass, interface=MyInterface)
        return ptr
    except:
        return None

def CType(obj, interface):
    """Casts obj to interface and returns comtypes POINTER or None"""
    try:
        newobj = obj.QueryInterface(interface)
        return newobj
    except:
        return None

def CLSID(MyClass):
    """Return CLSID of MyClass as string"""
    return str(MyClass._reg_clsid_)

def GetApp(app="ArcMap"):
    """app must be 'ArcMap' (default) or 'ArcCatalog'\n\
    Execute GetDesktopModules() first"""
    if not (app == "ArcMap" or app == "ArcCatalog"):
        print "app must be 'ArcMap' or 'ArcCatalog'"
        return None
    import comtypes.gen.esriFramework as esriFramework
    import comtypes.gen.esriArcMapUI as esriArcMapUI
    import comtypes.gen.esriCatalogUI as esriCatalogUI
    pAppROT = NewObj(esriFramework.AppROT, esriFramework.IAppROT)
    iCount = pAppROT.Count
    if iCount == 0:
        return None
    for i in range(iCount):
        pApp = pAppROT.Item(i)
        if app == "ArcCatalog":
            if CType(pApp, esriCatalogUI.IGxApplication):
                return pApp
            continue
        if CType(pApp, esriArcMapUI.IMxApplication):
            return pApp
    return None


def GetModule(sModuleName):
    """Import ArcGIS module"""
    from comtypes.client import GetModule
    sLibPath = GetLibPath()
    GetModule(sLibPath + sModuleName)


def GetDesktopModules():
    """Import basic ArcGIS Desktop libraries"""
    GetModule("esriFramework.olb")
    GetModule("esriArcMapUI.olb")

#My added function for checking edit session status
def ArcMap_GetEditSessionStatus():

    GetDesktopModules()
    GetModule("esriEditor.olb")
    import comtypes.gen.esriSystem as esriSystem
    import comtypes.gen.esriEditor as esriEditor
    pApp = GetApp()
    pID = NewObj(esriSystem.UID, esriSystem.IUID)
    pID.Value = CLSID(esriEditor.Editor)
    pExt = pApp.FindExtensionByCLSID(pID)
    pEditor = CType(pExt, esriEditor.IEditor)
    if pEditor.EditState == esriEditor.esriStateEditing:
        print "Edit session active"
        return True
    else:
        print "Not in an edit session"
        return False

1
这很好。我知道这是一篇过时的文章,但是如果您希望将其打包以便更便携,则可以将snippets模块制作为python软件包,并在其中包含comtypes。我为公司这样做,并将所有自定义Python模块都放置在网络共享上。每次有人安装/重新安装ArcGIS软件时,我都会让他们运行一个批处理文件,该文件会修改其Desktop.pth文件以包含网络共享的完整路径,因此每个人都可以自动导入所有内容。
crmackey '16

2

如何使用数据访问模块?您似乎可以使用此模块开始编辑会话。

一些警告:

  1. 我没有尝试过该模块,并且不确定是否与10.0兼容。(10.1中的新功能?)
  2. 示例1显示了with语句的使用。这是一个很好的实现范例,因为它很好地处理了潜在的异常。
  3. 您可以通过尝试在try / except语句中启动一个编辑会话来测试它是否已经存在。

实际上,当我开始这个项目时,我实际上是从在数据访问模块中使用Editor类开始的,但是使用它似乎并不重要。在我的脚本中包括“使用arcpy.da.Editor(workspace)作为编辑:”不会激活编辑器,而尝试stopOperation / stop。编辑不会停止编辑器。但是我可能做错了……
user18412

1

因此,这就是我解决无法控制是否有人在使用编辑工具的问题:

#Reference to mxd and layers script here. Then...
try:
    fields = ("OBJECTID")
    upCursor = arcpy.da.UpdateCursor(waterValves, fields)
    with upCursor as cursor:
        for row in cursor:
            pass
except:
    pythonaddins.MessageBox('You are not in an edit session', 'Warning', 0)

else:
#Rest of script

该脚本之所以起作用,是因为它试图在脚本中稍后具有另一个UpdateCursor的层上创建一个UpdateCursor。这违反了数据访问模块的行为。根据arcpy.da.UpdateCursor上的ESRI资源页面:

“使用不同的游标在同一工作空间上同时打开插入和/或更新操作需要启动编辑会话。”

我对此解决方案不满意,因为它比我想像的适当的arcpy脚本更像是一种hack。有更好的主意吗?


1
这只是一个主意,但是您可以尝试访问ArcObjects中的Editor对象并检查其属性EditState,这似乎是arcpy所缺少的吗?我从没有尝试过从python操作ArcObjects,但此线程讨论如何做到这一点?
Hornbydd
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.