C#ATIA

↑タイトル詐欺 主にCATIA V5 の VBA(最近はPMillマクロとFusion360APIが多い)

PreSelectイベントサンプル

こちらに記載した内容とちょっと関連してます。恐らく。
解決済み: Re: ValidateInputsEventHandlerのイベントによる呼び出しについて - Autodesk Community

本家のAPIフォーラムで質問した際のものは、
f:id:kandennti:20200122115241p:plain
SelectionCommandInput(要素を選択するやつ)が2個有り、希望としては
”2個共何かが選択された際にOKボタンが機能するようにしたい”
と言うことです。
何か処理する際に片方だけでは処理出来ないので、OKボタンは
押せない状態にしておくのが自然な事ですよね?
でもAPIフォーラムに記載した最初のコードでは実現できず、
さらに2個目でうまく行くと思ったのにそれでもNGだったのです。

教えて頂いたのは、SelectionCommandInputの選択制限数を
無制限にすれば機能するよ って事でした。
Fusion 360 Help

・・・
            i1 = inputs.addSelectionInput(_input1ID, _input1ID,  _input1ID)
            #i1.setSelectionLimits(1,1) #NG
            i1.setSelectionLimits(0) #OKだけど無制限に選択出来ちゃう
・・・

仮に、各SelectionCommandInputで1個づつでなければ処理出来ない場合は、
当然、選択数が無制限では困っちゃう場合があるので、他の何らかの方法で
防ぐ必要に迫られる事になります。

それを考えるとsetSelectionLimitsメソッド(プロパティじゃ無いんだな…)は、
1個の時のみ簡単に実装するための機能なんだなぁ と感じます。

つまり、そこまで拘るなら お前が頑張れ! って受け止めました。



と、ここまでが前置きです。
選択を防ぐ方法としては幾つか有りそうなのですが、恐らくCommandオブジェクトの
preSelectイベントが良さそうです。
Fusion 360 Help
・・・Helpの説明がやたらと長い。

記載によれば、2個を選択出来るようにして平面を選択フィルタとし、
お互いが並行でなければならなければ と言う条件の場合は
Fusion 360 Help
こちらだけでは不足してます。
OKボタンを押した後に、 "お前が選択した平面は平行じゃないから、中止するね" と
メッセージを出すのは、表示させる言葉をいくら丁寧にしても不親切。

preSelectイベントは選択直前の処理なのですが、マウスカーソルの下の面等の取得が
可能です。選択させたくない場合は、、、、Helpの説明がやたらと長い割には
そこの説明が抜け落ちてる。

class PreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        eventArgs = adsk.core.SelectionEventArgs.cast(args)

こんな感じのイベントハンドラを作った場合、argsはSelectionEventArgsオブジェクトなので、
Fusion 360 Help

        eventArgs.isSelectable = False

こんな感じにすると選択出来なくなります。これは対象となるオブジェクトを
選択不可にするわけじゃなく、一時的な事の様です。
f:id:kandennti:20200122115423p:plain
なるほど、是非ともHelpに記載して欲しい。

と言うことでサンプルです。

#Fusion360API Python script
#Author-kantoku
#Description-PreSelectイベントサンプル

import adsk.core, adsk.fusion, traceback

_commandId = 'PreSelectionEvent'
_SelIpt1ID = 'Selectioninput1'

_handlers = []
_app = None
_ui = None

class CommandDestroyHandler(adsk.core.CommandEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            adsk.terminate()
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class ValidateInputHandler(adsk.core.ValidateInputsEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.ValidateInputsEventArgs.cast(args)

            inputs = eventArgs.inputs
            i1 :adsk.core.SelectionCommandInput = inputs.itemById(_SelIpt1ID)

            # 選択が2個ならOKボタンを有効に
            if i1.selectionCount == 2:
                eventArgs.areInputsValid = True
            else:
                eventArgs.areInputsValid = False
                
        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class PreSelectHandler(adsk.core.SelectionEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            eventArgs = adsk.core.SelectionEventArgs.cast(args)

            i1 :adsk.core.SelectionCommandInput = eventArgs.firingEvent.activeInput
            if i1.selectionCount == 2:
                # 既に選択が2個なら許さない
                eventArgs.isSelectable = False
                return
                
            if i1.selectionCount < 1 :
                # 選択が0個なら問題なし
                return

            selGeo :adsk.core.Plane = i1.selection(0).entity.geometry
            preGeo :adsk.core.Plane = eventArgs.selection.entity.geometry

            # お互いが平面か確認して判断
            eventArgs.isSelectable = selGeo.isParallelToPlane(preGeo)

        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

class CommandCreatedHandler(adsk.core.CommandCreatedEventHandler):
    def __init__(self):
        super().__init__()
    def notify(self, args):
        try:
            cmd = args.command

            onDestroy = CommandDestroyHandler()
            cmd.destroy.add(onDestroy)
            _handlers.append(onDestroy)

            onValidateInput = ValidateInputHandler()
            cmd.validateInputs.add(onValidateInput)
            _handlers.append(onValidateInput)

            onPreSelect = PreSelectHandler()
            cmd.preSelect.add(onPreSelect)
            _handlers.append(onPreSelect)

            inputs = cmd.commandInputs
            i1 = inputs.addSelectionInput(_SelIpt1ID, _SelIpt1ID,  _SelIpt1ID)
            i1.setSelectionLimits(0)
            # 平面のみ
            filters = ['PlanarFaces','ConstructionPlanes']
            [i1.addSelectionFilter(s) for s in filters]

        except:
            if _ui:
                _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

def run(context):
    try:
        global _app, _ui
        _app = adsk.core.Application.get()
        _ui = _app.userInterface

        cmdDefs = _ui.commandDefinitions

        cmdDef = cmdDefs.itemById(_commandId)
        if cmdDef:
            cmdDef.deleteMe()

        cmdDef = cmdDefs.addButtonDefinition(_commandId, _commandId, _commandId)

        onCmdCreated = CommandCreatedHandler()
        cmdDef.commandCreated.add(onCmdCreated)
        _handlers.append(onCmdCreated)
        cmdDef.execute()

        adsk.autoTerminate(False)
    except:
        if _ui:
            _ui.messageBox('Failed:\n{}'.format(traceback.format_exc()))

こんな感じで動作します。選択数とOKボタンを見て頂きたいです。
(マウスカーソルが停止しているときは、クリックしまくってます)