ArcPyを介して、ArcMapが編集セッションにあるかどうかを確認していますか?


11

あるフィーチャクラス属性を別の属性クラスにコピーすることで、同僚のワークフローをスピードアップするのに役立つPythonアドインボタンを作成しました。これは、arcpy.UpdateCursor関数を使用して、ターゲットフィーチャクラスの行を更新します。現在存在するため、このボタンスクリプトは編集モードに関係なく実行できます。明らかに編集セッションで実行する場合、ユーザーは編集を停止して変更を保存しないことを選択できますが、スクリプトが編集セッション外で実行される場合はそうではありません。

ArcMapが現在編集セッションにない場合にスクリプトの実行を停止するチェックをスクリプトに追加するにはどうすればよいですか?

これは、ArcMap 10および10.1に関係します。


また、他のArcMapユーザーに確認して、編集セッションに参加しない限り、テーブルの更新が通常許可されないことを確認したいと思います。

では、このスクリプトは編集セッションの外でどのように実行されるのでしょうか。

このスクリプトは、リストから2番目のフィーチャクラステーブルを更新したときに、たまたま機能する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

データアクセスモジュールエディターは、標準のエディターとは独立して動作しているようです。アクティブな編集セッションのテストに関する追加のアイデアがあれば歓迎します。
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は編集セッションにない場合停止し、編集セッションにある場合は続行します。あなたの答えは反対のことをするようです。おそらく、それを好転させるのにそれほど時間はかからないでしょう。
ミダバロ

OPは既に彼の問題を解決しました。この投稿は、より一般的に役立つ機能を紹介するだけです。関数の使用方法をより明確にするために、例を変更しました。
Curtisの価格

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

4

ArcObjectsとPythonを一緒に使用してArcMapのエディターのステータスをチェックする新しい方法を学んだので、別の回答を投稿します。私の答えは、この投稿で言及されているように、Mark Cederholmによって行われた作業から大いに借りています。Python からArcObjectsにアクセスするにはどうすればよいですか?、およびマットウィルキーが「Snippits.py」ファイルで提供したコード例。最初の回答に記載されている手順に従って、comtypeをダウンロードしてインストールし、Snippets.pyスクリプトのコピーを取得する必要があります。以下のスクリプトの重要な機能のコピーを投稿しています。

関数ArcMap_GetEditSessionStatus()が呼び出されると、ArcMapのエディターの現在の状態がチェックされ、trueまたはfalseが返されます。これにより、ユーザーが私のツールを使用する準備ができているかどうか、または編集セッションを開始するようにプロンプ​​トが表示される必要があるかどうかを確認できます。この方法の欠点は、PythonでArcObjectsを使用する前にcomtypeをインストールする必要があるため、このパッケージを必要とするツールをマルチユーザーオフィス環境で共有できない可能性があることです。私の限られた経験では、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
これはうまくいきます。私はこれが古い投稿であることを知っていますが、これをパッケージ化してより移植性を高めたい場合は、スニペットモジュールをpythonパッケージとして作成し、その中にcomtypeを含めることができます。私はこれを会社のために行い、すべてのカスタムPythonモジュールをネットワーク共有に配置しました。誰かがArcGISソフトウェアをインストール/再インストールするたびに、ファイルを変更Desktop.pthしてネットワーク共有へのフルパスを含めるようにバッチファイルを実行させるので、誰でもすべてを自動的にインポートできます。
crmackey

2

データアクセスモジュールの使用についてはどうですか?このモジュールで編集セッションを開始できるようです。

いくつかの警告:

  1. 私はこのモジュールを試したことがなく、10.0と互換性があるかどうかはわかりません。(10.1の新機能?)
  2. 例1は、withステートメントの使用法を示しています。これは、潜在的な例外を適切に処理するため、実装するのに最適なパラダイムです。
  3. try / exceptステートメントで編集セッションを起動しようとすることで、編集セッションがすでにライブかどうかをテストできる場合があります。

このプロジェクトを始めたとき、私は実際にデータアクセスモジュールでEditorクラスを使用し始めましたが、それを使用することは重要ではないようでした。スクリプトに「with arcpy.da.Editor(workspace)as edit:」を含めてもエディターがアクティブにならず、stopOperation / stop.Editingを実行してもエディターが停止しませんでした。しかし、私はそれを間違って行っている可能性があります...
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スクリプトであると私が想像するよりもハックの方が多いためです。より良いアイデアは誰ですか?


1
これは単なるアイデアですが、ArcObjectsのEditorオブジェクトにアクセスして、そのプロパティEditStateを確認してみてください。これは、arcpyにはないようです。私はPythonからArcObjectsを操作しようとしたことがありませんが、このスレッドはそれを行う方法について話しますか?
Hornbydd 2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.