MenuBuilder メニューイベントの処理

Adobe AIR 1.0 およびそれ以降

NativeMenu のユーザー操作はイベント駆動型です。ユーザーがメニューアイテムを選択したり、メニューやサブメニューを開くと、NativeMenuItem オブジェクトによってイベントが送出されます。MenuBuilder フレームで作成した NativeMenu オブジェクトでは、個別の NativeMenuItem オブジェクトや NativeMenu にイベントリスナーを登録できます。これらのイベントの登録および応答の方法は、NativeMenu オブジェクトおよび NativeMenuItem オブジェクトを MenuBuilder フレームワークを使用せずに手動で作成した場合と同じです。詳しくは、 メニューイベント を参照してください。

MenuBuilder フレームワークでは、標準のイベント処理を補完する方法として、メニューデータソース内のメニューアイテムに select イベントハンドラー関数を指定できます。メニューアイテムデータソースに onSelect フィールドを指定すると、ユーザーがそのメニューアイテムを選択したときに、指定した関数が呼び出されます。例えば、MenuBuilder フレームワークを使用して読み込んだデータソースに次の XML ノードが含まれているとします。該当するメニューアイテムを選択すると、 doSave() という関数が呼び出されます。

<menuitem label="Save" onSelect="doSave"/>

onSelect フィールドは、XML データソースでは String です。JSON 配列では、関数名の String を使用できます。また、JSON 配列でのみ、関数への変数参照をオブジェクトとして使用できます。ただし、JSON 配列で関数への変数参照を使用する場合は、 onload イベントハンドラーの前または実行時にメニューを作成する必要があります。そうしない場合は、JavaScript セキュリティ違反が発生します。いずれの場合でも、指定した関数はグローバルスコープで定義する必要があります。

指定した関数が呼び出されると、その関数に対してランタイムから 2 つの引数が渡されます。最初の引数は、 select イベントから送出されるイベントオブジェクトです。このオブジェクトは Event クラスのインスタンスです。関数に渡される 2 番目の引数は、メニューアイテムの作成に使用されたデータを含む匿名オブジェクトです。このオブジェクトには次のプロパティがあります。各プロパティの値は、元のデータ構造の値と一致します。元のデータ構造に設定されていないプロパティの値は null になります。

  • altKey

  • cmdKey

  • ctrlKey

  • defaultKeyEquivalentModifiers

  • enabled

  • keyEquivalent

  • label

  • mnemonicIndex

  • onSelect

  • shiftKey

  • toggled

  • type

次の例では、NativeMenu イベントを試すことができます。この例には 2 つのメニューが含まれています。ウィンドウおよびアプリケーションメニューは、XML データソースを使用して作成されます。 <ul> エレメントおよび <li> エレメントで示されるアイテムのリストのコンテキストメニューは、JSON 配列データソースを使用して作成されます。画面のテキスト領域には、ユーザーがメニューアイテムを選択したときに、各イベントに関する情報が表示されます。

アプリケーションのソースコードを次に示します。

<html> 
    <head> 
        <title>Menu event handling example</title> 
        <script type="text/javascript" src="AIRAliases.js"></script> 
        <script type="text/javascript" src="AIRMenuBuilder.js"></script> 
        <script type="text/javascript" src="printObject.js"></script> 
        <script type="text/javascript"> 
            function fileMenuCommand(event, data) { 
                print("fileMenuCommand", event, data); 
            } 
             
            function editMenuCommand(event, data) { 
                print("editMenuCommand", event, data); 
            } 
             
            function moveItemUp(event, data) { 
                print("moveItemUp", event, data); 
            } 
             
            function moveItemDown(event, data) { 
                print("moveItemDown", event, data); 
            } 
             
            function print(command, event, data) { 
                var result = ""; 
                result += "<h1>Command: " + command + '</h1>'; 
                result += "<p>" + printObject(event) + "</p>"; 
                result += "<p>Data:</p>"; 
                result += "<ul>"; 
                for (var s in data) { 
                    result += "<li>" + s + ": " + printObject(data[s]) + "</li>"; 
                } 
                result += "</ul>"; 
                 
                var o = document.getElementById("output"); 
                o.innerHTML = result; 
            } 
        </script> 
        <style type="text/css"> 
            #contextList { 
                position: absolute; left: 0; top: 25px; bottom: 0; width: 100px; 
                background: #eeeeee; 
            } 
            #output { 
                position: absolute; left: 125px; top: 25px; right: 0; bottom: 0; 
            } 
        </style> 
    </head> 
    <body> 
        <div id="contextList"> 
            <ul> 
                <li>List item 1</li> 
                <li>List item 2</li> 
                <li>List item 3</li> 
            </ul> 
        </div> 
        <div id="output"> 
            Choose menu commands. Information about the events displays here. 
        </div> 
        <script type="text/javascript"> 
            var mainMenu = air.ui.Menu.createFromXML("mainMenu.xml"); 
            air.ui.Menu.setAsMenu(mainMenu); 
             
            var listContextMenu = air.ui.Menu.createFromJSON("listContextMenu.js"); 
            air.ui.Menu.setAsContextMenu(listContextMenu, "contextList") 
             
            // clear the default context menu 
            air.ui.Menu.setAsContextMenu(null); 
        </script> 
    </body>| 
</html>

メインメニューのデータソース(「mainMenu.xml」)を次に示します。

<?xml version="1.0" encoding="utf-8" ?> 
<root> 
    <menuitem label="File"> 
        <menuitem label="New" keyEquivalent="n" onSelect="fileMenuCommand"/> 
        <menuitem label="Open" keyEquivalent="o" onSelect="fileMenuCommand"/> 
        <menuitem label="Save" keyEquivalent="s" onSelect="fileMenuCommand"/> 
        <menuitem label="Save As..." keyEquivalent="S" onSelect="fileMenuCommand"/> 
        <menuitem label="Close" keyEquivalent="w" onSelect="fileMenuCommand"/> 
    </menuitem> 
    <menuitem label="Edit"> 
        <menuitem label="Cut" keyEquivalent="x" onSelect="editMenuCommand"/> 
        <menuitem label="Copy" keyEquivalent="c" onSelect="editMenuCommand"/> 
        <menuitem label="Paste" keyEquivalent="v" onSelect="editMenuCommand"/> 
    </menuitem> 
</root>

コンテキストメニューのデータソース(「listContextMenu.js」)を次に示します。

[ 
    {label: "Move Item Up", onSelect: "moveItemUp"}, 
    {label: "Move Item Down", onSelect: "moveItemDown"} 
]

printObject.js ファイルのコードを次に示します。このファイルに含まれている printObject() 関数は、アプリケーションで使用されますが、例でのメニュー操作には影響しません。

function printObject(obj) { 
    if (!obj) { 
        if (typeof obj == "undefined") { return "[undefined]"; }; 
        if (typeof obj == "object") { return "[null]"; }; 
        return "[false]"; 
    } else { 
        if (typeof obj == "boolean") { return "[true]"; }; 
        if (typeof obj == "object") { 
            if (typeof obj.length == "number") { 
                var ret = []; 
                for (var i=0; i<obj.length; i++) { 
                    ret.push(printObject(obj[i])); 
                } 
                return ["[", ret.join(", "), "]"].join(" "); 
            } else { 
                var ret = []; 
                var hadChildren = false; 
                for (var k in obj) { 
                    hadChildren = true; 
                    ret.push ([k, " => ", printObject(obj[k])]); 
                } 
                if (hadChildren) { 
                    return ["{\n", ret.join(",\n"), "\n}"].join(""); 
                } 
            } 
        } 
        if (typeof obj == "function") { return "[Function]"; } 
        return String(obj); 
    } 
}