NXML Event Handling

Nexaweb は、onMouseOver などのハードウェアの直接応答から、onStateChange などの論理イベントに至るまで、さまざまなレベルのイベントを処理する機能を備えています。Nexaweb に対応したアプリケーションは、次の方法によってこのようなイベントを処理します。
  • NXML マクロ コマンド
  • JSP ページ、サーブレット、静的ページなど、サーバーサイドのリソース
  • MCO やシステム サービスへの呼び出しを含むクライアントサイドの Java コード
ここでは次のトピックについて説明します。
  • イベントの概要
  • マクロを使用したイベントの処理
  • サーバーサイドのイベント処理
  • クライアントサイドのイベント処理
  • イベントの順序付け
イベントの概要
イベント方式のプログラミングでは、アプリケーションが反応する必要のある各イベントに対してイベントハンドラを定義します。このようなイベントには次のものがあります。
  • キーストローク、ボタンのクリック、コンポーネント上でのマウスのホバーリングなどの物理的イベント
  • ドロップダウン リストや状態を変更するチェックボックスで行われる選択など、より高度な UI イベント
このようなイベントのイベントハンドラには、次のものがあります。
  • マクロ (UI を定義する XML に含まれるクライアントサイドのスクリプト)
  • サーバーサイドのドキュメント
  • ユーザー定義のクライアント クラスまたは MCO のメソッド
いずれの場合も、 イベントハンドラは、必要とされるアプリケーションの機能を十分に実行して、特定のユーザーアクションに対して適切に反応します。Nexaweb クライアントは、イベントに依存してユーザーコマンドに応答します。Nexaweb クライアントは約 30 のイベントを定義します。Nexaweb クライアントが各コンポーネントに対して発生させることが可能なイベントの詳細については、UI ドキュメントを参照してください。
どのようなイベントの場合でも、クライアントはイベントを説明する情報を含むイベントオブジェクトを作成します。クライアントはイベントオブジェクトを作成した後で、次のいずれかを実行します。
  • マクロを実行する
  • イベント情報をエンコードして、HTTP を使用してサーバーサイドのハンドラに送信する
  • イベント オブジェクトをクライアントサイドの MCO ハンドラに渡す
次のコード例を使用して説明します。

<button text="my button" onCommand="buttonclick.jsp" />

onCommand イベントがサーバー上の

buttonclick.jspに発生して、自動的に次の属性を URL パラメータとして渡します。
  • id 属性 - ユーザー定義の ID または Nexaweb で指定された ID
  • event 属性 - この例では 'onCommand'

マクロのイベントハンドラの使用

クライアントサイドのマクロスクリプトを UI ドキュメントで定義して、クライアントイベントを処理できます。以下に示す例では、次の内容が定義されます。
  • changeLabelTextMacro マクロ
  • ボタンの onCommand ハンドラを macro://changeLabelTextMacro.execute() として定義
このマクロでは、ユーザーがボタンをクリックすると、クライアントがラベルのテキストを "Some new text" に更新します。

 

<macro:macro xmlns:macro="http://nexaweb.com/macro" name="changeLabelTextMacro">
<xu:modifications document="nxml" version="1.0" xmlns:xu="http://nexaweb.com/xupdate">
<xu:set-attribute select="id(''mylabel'')">
<xu:attribute name="text" value="Some new text"/>
</xu:set-attribute>
</xu:modifications>
</macro:macro>
<button onCommand="macro://changeLabelTextMacro.execute()" text="Change mylabel text" />
<label id="mylabel" text="This is some text" />

 

サーバーサイドのイベント処理

クライ アントイベントをサーバーに発生させる機能は、サーバーがクライアントサイドでのユーザーアクションに関与する場合に非常に強力なツールとなります。この ハンドラは、JSP ページ、サーブレット、または XUpdate 文を使用する静的ページの場合があります。

次の例では、JSP ページがイベントパラメータを受け取って XUpdate ドキュメントを生成し、クライアントに返すプロセスを示します。

UI ドキュメントはハンドラを次のように指定します。

 

<button onCommand="changeLabelText.jsp" text="Change mylabel text" />
<label id="mylabel" text="This is some text" />

 

changeLabelText.jspは、サーバーサイドでイベントを処理します。

 

<xu:modifications document="nxml" version="1.0" xmlns:xu=http://nexaweb.com/xupdate">
<xu:set-attribute select="id('mylabel')">
<xu:attribute name="text" value="Button <%= (request.getParameter("id") + " fired event " + request.getParameter("event")) %>"/>
</xu:set-attribute>
</xu:modifications>

 

ここでは、サーバーサイドの JSP ページでrequest.getParameter("id")とrequest.getParameter("event")を使用して、ボタン要素の id と発生するevent の名前を取得します。onCommand属性を設定する際に、この idevent の値を指定する必要はありません。これらの値は、実行時に URL に添付されます。さまざまな UI 要素から発生させることができるイベントについては、UI リファレンスドキュメントを参照してください。

 

サーバーサイドでクライアントイベントを処理する際にサーバーセッションまたはサーバーサイドのドキュメントにアクセスする必要がある場合は、次を呼び出すことができます。
SessionManager smgr = ServiceManager.getSessionManager();
ServerSession nxsession = smgr.findByRequest(request);

 

サーバーの UI DOM が有効になっている場合は、次のコードを使用して、サーバーサイドで UI ドキュメントを取得できます。

Document uiDom = nxsession.getDocumentRegistry().getUiDocument();

また、返されたDocumentを調べるか、com.nexaweb.xmlで API を使用して、名前によって要素を検索することができます。
 

クライアントサイドのイベント処理
サーバーにイベントを通知する必要がない場合は、システムサービスまたは MCO (Managed Client Object) と呼ばれる、顧客に よって作成されたクライアントサイドのクラスへの呼び出しによって直ちにイベントを処理することができます。このクライアントサイドのメソッドにより、ク ライアント UI の更新、各種ドキュメントの作成または更新、さらにサーバーへの再接続を行うことができます。次の例では、イベントを処理するためにクライアントサイドの コード呼び出し機能を使用する方法を示します。

1. 簡単な要素へのアクセスと属性の変更
この例は、clientSessionlabel 要素を順に取得するコードを示します。これらの要素を取得した後、ClientSession のgetEventHandler().getClientEvent()を呼び出して ClientEvent オブジェクトを取得します。このオブジェクトはイベントのパラメータを提供します。使用可能なパラメータはイベントの種類によって異なります。

この例では、UI ドキュメントは MCO を宣言してハンドラを指定します。

 

<mco:declarations xmlns:mco="http://nexaweb.com/mco">
<mco:mco id="eventMco" src="pkg.EventHandlers"/>
</mco:declarations>
<nxml>
<rootPane>
<flowLayout/>
<button onCommand="mco://eventMco.changeLabelText()" text="Change mylabel text" />
<label id="mylabel" text="This is some text" />
</rootPane>
</nxml>

 


このハンドラは、ユーザーによって作成されたEventHandlers.java内にあるchangeLabelTextメソッドです。

 

private static final XPath LABEL_XPATH =
XPathFactory.createXPath("id('mylabel')");

public void changeLabelText(){
ClientSession s = getSession();
Element label = LABEL_XPATH.evaluateAsElement(
s.getDocumentRegistry().getUiDocument());

Object domLock =
label.getOwnerDocument().getDomSynchronizationObject();

ClientEvent event = s.getEventHandler().getClientEvent();
synchronized(domLock){
label.setAttribute("text", "some new text from "
+ event.getParameter("id") + ":"+ event.getParameter("event"));
}
}

 

2. 時間のかかるクライアンサイドタスクの実行


イベント ハンドラで時間のかかるタスクを行う場合、待機中のカーソルを使用してユーザーに待機するよう通知した後、別のスレッドでタスクを実行できます。次の例で は、これを実行する方法を示します。この例は、ラベルの更新を完了するまでに 5 秒かかるタスクを示しています。このタスクがクライアントで実行中であることをユーザーに知らせるために、displayService.pushGlassPane()を実行して待機中のカーソルを表示し、この間ユーザーが入力を行わないようにします。タスクが終了すると、displayService.popGlassPane() は待機中のカーソルを解除して再び入力を受け付けます。

次に、この UI ドキュメントを示します。

 

<button onCommand="mco://eventMco.waitOnLongTask()" text="Change mylabel text" />
<label id="mylabel" text="This is some text" />

 


次に、MCO ハンドラのメソッドを示します。

 

public void waitOnLongTask(){
final ClientSession s = getSession();
s.getDisplayService().pushGlassPane();
new Thread(new Runnable(){
public void run(){
try{
Thread.sleep(5000);
onChangeLabelText();
}catch(Exception e){
e.printStackTrace();
}finally{
s.getDisplayService().popGlassPane();
}
}
}).start();
}
}

 

3. onBeforeActiveLostイベントハンドラ

これは、現要素からフォーカスがロストする前に、要素に検証コードを追加する際、または他の状態を確認する際使用することができる特別なイベントです。クライアントは要素の onActiveLost を発生させる前に onBeforeActiveLost イベントハンドラを発生させます。イベントハンドラが false を返す時、イベントは消費されます。つまり、現在のフォーカス要素にフォーカスは残ります。クライアントサイドのMCO だけが、onBeforeActiveLost イベントハンドラをハンドルすることができます。なぜならマクロやサーバーサイドのハンドラはブール値を戻すことができないからです。onBeforeActiveLost ハンドラは非常に早く実行しなくてはならないことに注意して下さい。

次の例は textField の入力長さが厳密に10 文字を維持していることを示しています。こうすることにより、10文字以下もしくは以上の場合、ユーザーが textfField をクリックしたりタブから離れることができないようにします。

次の例は UI 文書を示しています :

 <textField text="input 10 characters only" onBeforeActiveLost="mco://eventMco.onBeforeActiveLost()"/>

次の例は MCO ハンドラメソッドを示しています:

public boolean onBeforeActiveLost(){
   ClientSession s = McoContainer.getSession();
   ClientEvent event = s.getEventHandler().getClientEvent();
   String id = event.getParameter("id");
   Element element = 
      s.getDocumentRegistry().getUiDocument().getElementById(id);
   String text = (String)element.getAttribute("text");
   if ( text.length() == 10)
     return true;
   else
     return false;
   }
 } 

 

イベントの順序

Nexaweb Platform は多くの異なるイベントを提供します。中にはボタンの onCommand や onMouseUp のように順番に実行されるものもあります。次ではイベント発生順序に関する一般的な情報を提供しています :

メモ: 順番に発火する可能性がある、複数のイベントをハンドリングする際、気を付けて下さい。例えば最初のハンドラにフラグを設定する、または2番目のハンドラをリダイレクトするなど。

  • onBeforeActiveLost イベントはフォーカスを失う際に発生します。クライアントが onBeforeActiveLost イベントに false を戻す場合、コンポーネントはフォーカスを失わず、他のイベントは発生しません。
  • ユーザが <Enter> キーを押下する際、onCommand イベントが常に最初に実行されます。
  • 物理的イベントから直接発生するイベントに関しては、次の順番でイベントが発生します:
    1. onKeyDown (<Enter>以外のキーボードアクションの場合) または onMouseDown (マウスクリックの場合) イベントが最初に発火します。
    2. その後、フォーカスに変更がある際、テキストに変更のあるテキストコンポーネントがフォーカスを失った場合 onEdit イベントが先行します。
    3. 次に onActiveLost が発生し、onActiveGained が続きます。
    4. フォーカス変更後、onStateChange のような上位レベルの合成イベントが続きます。
    5. 次に、キーボードイベントに対し、onKeyCharが発生します。
    6. リリースでは、onKeyUp が キーボードに対し発生するか、マウスによる onMouseUp が発生します (ボタンのonCommandの後) 。