ตรวจสอบผ่าน ArcPy ว่า ArcMap อยู่ในช่วงแก้ไขหรือไม่?


11

ฉันได้สร้างปุ่ม Python add-in ที่ช่วยเร่งขั้นตอนการทำงานของเพื่อนร่วมงานด้วยการคัดลอกคุณลักษณะคลาสคุณลักษณะหนึ่งไปยังอีก มันใช้ฟังก์ชัน arcpy.UpdateCursor เพื่ออัปเดตแถวในคลาสคุณลักษณะเป้าหมาย เนื่องจากมันมีอยู่ตอนนี้สคริปต์ปุ่มนี้สามารถทำงานได้โดยไม่คำนึงถึงโหมดการแก้ไข เห็นได้ชัดว่าเมื่อมันทำงานในเซสชั่นการแก้ไขผู้ใช้สามารถเลือกที่จะหยุดการแก้ไขและไม่บันทึกการเปลี่ยนแปลง แต่ไม่ใช่ในกรณีที่สคริปต์ทำงานนอกเซสชันการแก้ไข

ฉันจะเพิ่มการตรวจสอบไปยังสคริปต์ที่จะหยุดสคริปต์ไม่ให้ทำงานได้อย่างไรหาก ArcMap ไม่ได้อยู่ในเซสชันการแก้ไขในปัจจุบัน

สิ่งนี้เกี่ยวข้องกับ ArcMap 10 & 10.1


ฉันต้องการตรวจสอบกับผู้ใช้ ArcMap คนอื่น ๆ เพื่อตรวจสอบว่าการอัปเดตตารางไม่ได้รับอนุญาตตามปกติโดยไม่ต้องอยู่ในเซสชันแก้ไข

ดังนั้นสคริปต์นี้ทำงานนอกเซสชันแก้ไขอย่างไร

สคริปต์นี้ยังทำให้เกิดคำถามอื่นเกี่ยวกับลำดับการเลือกที่ดูเหมือนว่าบังเอิญ ArcMap ดำเนินการที่เพิ่งเกิดขึ้นกับฉันเมื่อฉันอัปเดตตารางคลาสคุณลักษณะที่ 2 จากรายการ แต่นั่นเป็นอีกวัน

นี่คือสคริปต์ที่ใช้งานได้ในขณะนี้ (ไม่มีการใช้งานเครื่องมือแก้ไข 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

คุณสามารถให้ข้อมูลเพิ่มเติมเล็กน้อยได้หรือไม่ อะไรนำคุณไปสู่ข้อสรุปนี้สำหรับพวกเราที่ยังไม่ได้สำรวจโมดูล
Jay Laura

คำตอบ:


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 Addin Toolbar ฉันเพิ่มส่วนขยายที่ฟังการแก้ไขเพื่อเริ่มต้นหรือสิ้นสุด ฉันมีปุ่มทั้งหมดของฉันบนแถบที่ตั้งไว้ที่: 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

4

ฉันโพสต์คำตอบอื่นเพราะฉันได้เรียนรู้วิธีใหม่ในการตรวจสอบสถานะของเครื่องมือแก้ไขใน ArcMap โดยใช้ ArcObjects และ Python ด้วยกัน คำตอบของฉันยืมมาอย่างหนักจากงานที่ทำโดย Mark Cederholm ตามที่อ้างอิงในโพสต์นี้: ฉันจะเข้าถึง ArcObjects จาก Python ได้อย่างไร และตัวอย่างรหัสที่ Matt Wilkie จัดหาให้ในไฟล์ "Snippits.py" ของเขา คุณจะต้องทำตามคำแนะนำที่ให้ไว้ในคำตอบแรกเพื่อดาวน์โหลดและติดตั้ง comtypes แล้วรับสำเนาของสคริปต์ Snippets.py ฉันกำลังโพสต์สำเนาของฟังก์ชั่นที่สำคัญจากสคริปต์ด้านล่าง

เมื่อเรียกใช้ฟังก์ชัน ArcMap_GetEditSessionStatus () จะตรวจสอบสถานะปัจจุบันของตัวแก้ไขใน ArcMap และส่งกลับค่าจริงหรือเท็จ สิ่งนี้ช่วยให้ฉันตรวจสอบว่าผู้ใช้พร้อมที่จะใช้เครื่องมือของฉันหรือไม่หรือพวกเขาจำเป็นต้องได้รับพร้อมท์ให้เริ่มเซสชันการแก้ไขหรือไม่ ข้อเสียของวิธีนี้คือความต้องการในการติดตั้ง comtypes ก่อนที่จะใช้ ArcObjects ใน Python ดังนั้นการแชร์เครื่องมือที่ต้องใช้แพ็คเกจนี้ในสภาพแวดล้อมสำนักงานผู้ใช้หลายคนอาจไม่สามารถทำได้ จากประสบการณ์ที่ จำกัด ของฉันฉันไม่แน่ใจว่าจะรวมทุกอย่างเข้าด้วยกันอย่างไรเพื่อให้สามารถแบ่งปันได้ง่ายในฐานะเครื่องมือเสริม 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
มันใช้งานได้ดี ฉันรู้ว่านี่เป็นโพสต์เก่า แต่ถ้าคุณต้องการจัดทำแพ็กเกจนี้จึงพกพาได้มากขึ้นคุณสามารถสร้างโมดูลเกร็ดเล็กเกร็ดน้อยเป็นแพคเกจหลามและรวม comtypes ไว้ด้วย ฉันทำสิ่งนี้เพื่อ บริษัท ของฉันและฉันได้วางโมดูล Python ที่กำหนดเองทั้งหมดของเราบนเครือข่ายที่ใช้ร่วมกัน ทุกครั้งที่มีคนติดตั้ง / ติดตั้งซอฟต์แวร์ ArcGIS อีกครั้งฉันจะให้พวกเขาเรียกใช้แบตช์ไฟล์ที่แก้ไขได้Desktop.pthไฟล์เพื่อรวมเส้นทางแบบเต็มไปยังเครือข่ายที่ใช้ร่วมกันเพื่อให้ทุกคนสามารถนำเข้าทุกสิ่งโดยอัตโนมัติ
crmackey

2

วิธีการใช้งานdata access module ? ดูเหมือนว่าคุณจะสามารถเริ่มเซสชันการแก้ไขด้วยโมดูลนี้

คำเตือนบางประการ:

  1. ฉันยังไม่ได้ลองใช้โมดูลนี้และฉันไม่แน่ใจว่ามันเข้ากันได้กับ 10.0 หรือไม่ (ใหม่ใน 10.1?)
  2. ตัวอย่างที่ 1 แสดงการใช้withคำสั่ง นี่เป็นกระบวนทัศน์ที่ยอดเยี่ยมในการดำเนินการตามที่จัดการข้อยกเว้นที่อาจเกิดขึ้นได้เป็นอย่างดี
  3. คุณอาจสามารถทดสอบว่าเซสชันการแก้ไขนั้นใช้งานได้จริงหรือไม่โดยพยายามเปิดใช้งานหนึ่งรายการในtry / exceptคำสั่ง

จริง ๆ แล้วฉันเริ่มต้นด้วยการใช้คลาส Editor ใน data access module เมื่อฉันเริ่มโครงการนี้ แต่ดูเหมือนว่าการใช้จะไม่สำคัญ การรวม "กับ arcpy.da.Editor (เวิร์กสเปซ) เป็นการแก้ไข:" ในสคริปต์ของฉันไม่ได้เปิดใช้งานเครื่องมือแก้ไขและลองหยุดการทำงาน / หยุดการแก้ไขไม่ได้หยุดโปรแกรมแก้ไข แต่ผมอาจจะทำมันผิด ...
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 อื่นในสคริปต์ สิ่งนี้ละเมิดพฤติกรรมของ data access module ตามหน้าแหล่งข้อมูล ESRI ใน arcpy.da.UpdateCursor:

"การเปิดการแทรกและ / หรือการอัปเดตการดำเนินงานพร้อมกันบนพื้นที่ทำงานเดียวกันโดยใช้เคอร์เซอร์ที่แตกต่างกันต้องเริ่มเซสชันการแก้ไข"

ฉันไม่พอใจกับการแก้ปัญหานี้เพราะมันเป็นแฮ็คมากกว่าสิ่งที่ฉันคิดว่าเป็นสคริปต์ arcpy ที่เหมาะสม คิดยังไงดี


1
นี่เป็นเพียงแนวคิด แต่คุณสามารถลองเข้าถึงวัตถุ Editor ใน ArcObjects และตรวจสอบคุณสมบัติ EditState ซึ่งดูเหมือนจะเป็นสิ่งที่ขาดหายไปจาก arcpy? ฉันไม่เคยพยายามจัดการ ArcObjects จากไพ ธ อน แต่เธรดนี้พูดถึงวิธีการทำ
Hornbydd
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.