要約: | - Curl® 言語で記述されたアプレットは、目標で起動するイベント を使用してメッセージをプログラムに送ります。
- イベントは Curl アプレットをインタラクティブにするための重要なキーになります。
- イベント ハンドラは EventHandler クラスのオブジェクトを意味します。
- ダイナミック イベント ハンドラは、特定の EventTarget オブジェクトにアタッチする EventHandler オブジェクトです。
|
Curl アプレットは、目標で起動するイベントを使用して、プログラムのコンポーネント間でメッセージを送信したり、テキスト フィールドへの入力やオブジェクト上でのマウスの移動など、画面の特定の目標オブジェクトに影響する、ユーザーのマウスの操作についてプログラムに通知します。イベントが発生したことが目標ターゲットに通知されると、目標ターゲットはそれに応えて 1 つまたは複数のイベント ハンドラを呼び出します。
この章では、イベント、イベント目標、イベントの作成や起動の方法、およびイベントの起動に対して実行されるイベント ハンドラの種類について説明します。ここでは、キーボードやマウスを使用してアプレット ウィンドウと交信するときに生成されるイベントについて詳しく説明します。
イベント目標として動作するオブジェクトからイベントが起動されます。イベント目標の例としては、クリックするオブジェクトやドラッグして選択するテキストがあります。
オブジェクトは、
EventTarget のサブクラスになっているときに限り
Event の目標になります。すべてのグラフィック オブジェクトは
EventTarget クラスから継承しているので、目標になる可能性があります。
EventTarget オブジェクトには、関連付けられているダイナミック イベント ハンドラのリストがあります。一致するイベントがオブジェクトで起動されると呼び出されます。
ポインタがグラフィック オブジェクト上にあるときにマウス ボタンをクリックするような特定のイベント活動が発生すると、その種の活動を表すイベント オブジェクトが生成され、そのグラフィック オブジェクトが目標となり、イベントが
起動されます。次の例では、イベント目標は
CommandButton で、その上をクリックすると
Action イベントが
CommandButton で起動されます。
例:
単純なアクション イベント ハンドラ |
|
{CommandButton
label="Click me!",
{on Action at btn:CommandButton do
set btn.label = "Thank you."
}
}
| |
単語
on で始まるソース コードは、この例では
CommandButton にアタッチされるイベント ハンドラを作成します。イベント ハンドラにより、
CommandButton は、
Action イベントの一種である
PointerRelease イベントに対応してボタンのラベルおよびコントロールの色を変更します。
通常は、任意のイベントを使用して、他のイベントの起動のような、一連の操作を知らせたり、アプレットの状態を変更したりすることができます。それらの操作のソース コードはイベント ハンドラに含まれています。目標オブジェクトには複数のイベント ハンドラを含めることができます。各ハンドラは、一定のタイプのイベントが目標で起動されるとそのソース コードを実行します。イベント ハンドラ内のソース コードは他の目標でイベントを再起動することができます。
イベント 体系を簡単に要約すると次のようになります。
イベント 体系 | - ユーザーがマウスまたはキーボードを使用して、画面上のグラフィック オブジェクトに対していくつかの動作を行います。
- その動作を表すイベントがインスタンス化され、該当する目標オブジェクトで起動されます。
- 目標オブジェクトにアタッチされ、このイベントに対応する 1 つまたは複数のイベント ハンドラが実行されます。
- 任意のイベント ハンドラが同じイベント (または新たなイベント) を他の目標オブジェクトで起動し、他のイベント ハンドラを始動させることがあります。
|
同種のイベントを再び起動するアクションをイベント ハンドラが実行するといった、
再帰的なイベント ハンドラの呼び出しは回避する必要があります。
例えば、
ViewResizeEvent のハンドラが表示サイズを変更する場合や、
FocusIn イベント ハンドラがキーボード フォーカスを別のオブジェクトに移動する場合がそうです。
この状況を防ぐ、最も簡単な方法は、
{after 0s do ...} を使用して、
新しいイベントを引き起こすコードを実行します。次のコード フラグメントを検討してみましょう。
{on FocusIn do
{after 0s do
|| code-that-changes-keyboard-focus
}
}
キーボード フォーカスを変更するコードは、現在のイベントが完全に処理された後でのみ実行され、
起こり得る再帰が回避されます。式を {after 0s do body} 内に挿入すると、
タイマー イベントは他にイベントが無い場合のみに処理されるため、
body をイベント キューの終わりに追加するのと同様の効果が得られます。
各 Curl アプレットは イベント キュー を保持しています。イベント キュー上の各ノードはイベントおよびそのイベントが起動されるイベント目標で構成されます。
ユーザー インターフェイスがアクティブなとき、Curl® ではイベント ループと呼ばれるイベントに関連する操作の標準シーケンスを繰り返し実行します。イベント ループは、イベント キューが空になるたびに、ユーザー インターアクションによって、イベント キューに新しいイベント ノードが生成されるのを待ちます。イベント キューが空でないときは、キューの前面にあるイベント ノードが移動され、その指定された目標でイベントが起動され、イベントが要求どおりに処理されます。
頻繁に必要になることはありませんが、
EventTarget.enqueue-event を呼び出してイベントをイベント キューに追加することができます。これは、キューに入れられたイベントのハンドラが現在のイベント (およびキュー内で新しいイベントの前にあるその他のイベント) が処理されるまで実行されないので、
非同期イベント処理と呼ばれます。イベント キューを介さずにイベントをすぐに目標で起動したい場合、
EventTarget.handle-event を呼び出すことができます。これは、現在のイベント ハンドラ (ある場合) から戻る前に新しいイベントが直ちに処理されるので、
同期イベント処理と呼ばれます。
イベント ハンドラ は、正確には、
EventHandler クラスのオブジェクトを意味します。このオブジェクトには、オブジェクトが応答するイベント タイプ (イベント サブクラスの 1 つ) およびそのイベントのタイプに応答して実行されるプロシージャの両方が含まれます。
イベント ハンドラのプロシージャはイベントに対応して実行されるオブジェクトのアクティブな部分なので、イベント ハンドラ オブジェクトとその中に含まれるプロシージャとの違いを見過ごしがちです。イベント ハンドラのコードは指定されたクラスのイベントに対してのみ実行されることを覚えておくことが重要です。
イベント ハンドラにはいくつかの種類があります。オブジェクトの 1 つのインスタンスにアタッチされているイベント ハンドラを
ダイナミック イベント ハンドラといいます。最も広く使用されるイベント ハンドラで、任意の
EventTarget オブジェクトにアタッチすることができます。
各
EventTarget オブジェクトはダイナミック
EventHandler のリストを保持しています。
EventTarget クラスには、
EventHandler のリストにイベント ハンドラを追加および削除するメソッドがあります。イベントが目標で起動されると、目標はイベントのデータ型をリスト上にあるすべてのイベント ハンドラのイベント クラスと比較します。最後に追加されたハンドラから始まってリストの上方へ向かい、イベント クラスの一致する各ハンドラを起動します。複数のイベント ハンドラが所定のイベントに適用される可能性もあります。
次のセクションでは、ダイナミック イベント ハンドラの書き方について説明しますが、もっともよく使用されるタイプは特殊な
on 式を使用して作成されます。(次のセクション 「
on 式の使い方」を参照してください。)
Events はアプレットの実行時に再利用されることがよくあります。参照を作成した Event が再利用される場合、格納する情報は不正確になります。イベント ハンドラはハンドラが返されると、その後は、Event をグローバル変数に割り当てたりフィールドに格納することによって、イベントへの参照を保持するべきではありません。
特定のオブジェクトに対してダイナミック イベント ハンドラを作成するための主要なステップは次の通りです。
- イベント ハンドラ プロシージャのコードを記述する
- 適用するイベント クラスを指定する
- コードを特定のオブジェクト (イベント目標) にアタッチする
on 式を使用して、ステップ 1 と 2 を同時に実行することができます。この式にはいくつかの変化形があります。さらに、ステップ 3 でイベント ハンドラを目標オブジェクトにアタッチする方法が 2 つあります。
1 つ目は、イベント目標オブジェクトを作成するときに、次のようにしてイベント ハンドラにその他の引数をインクルードする方法です。
例:
イベント ハンドラを目標にインクルードする |
|
{CommandButton
label = "Do not press!",
|| create an event handler for Action events on this button
{on Action do
{popup-message "Why did you do that?"}
}
}
| |
もう 1 つは、目標オブジェクトを作成した後、その目標オブジェクト上でadd-event-handlerを開始する方法です。
例:
EventTarget.add-event-handler メソッドの使用 |
|
{value
let target:CommandButton =
{CommandButton
label = "Do not press!"
}
|| create an event handler and add it to the button already created
{target.add-event-handler
{on Action do
{popup-message "Why did you do that?"}
}
}
target
}
| |
特別な on 式にはいくつかのスタイルがあります。単純なフォームの構文を次に示します。 {on event-class do body}
- event-class は、処理するイベントのクラスを指定します。
- body は、イベント ハンドラ プロシージャのコードです。
次に示すようにして、このイベント ハンドラをグラフィック オブジェクトにアタッチすることができます。
例:
on 式の最も単純なフォーム |
|
{CommandButton
label={center {bold Invokes an event handler when clicked}},
|| Attach following event handler to this CommandButton
{on Action do
{popup-message
title="Your Message",
"This is a user message dialog."
}
}
} ||CommandButton
| |
on 式の他のスタイルを使用すると、イベント ハンドラの対応する特定のイベントに変数名をバインドし、メソッドを呼び出したりそのイベントのプロパティを調べることができます。同様に、変数名をイベント目標にバインドし、そのメソッドやプロパティにアクセスすることができます。
スタイル | 説明 |
{on event-type do body} | イベント タイプのみ指定 |
{on event-var:event-type do body} | 変数をイベントにバインド |
{on event-type at target-var[:target-type]} do body} | 変数を目標にバインド。target-type が指定されていない場合、既定では any になります。 |
{on event-var:event-type at target-var[:target-type] do body} | 変数をイベントと目標の両方にバインド |
すべてのスタイルで次のようになります。
- event-var は起動されたイベントの変数を定義します。メソッドまたはイベントのプロパティへのアクセスが必要な場合、event-var を使用します。
- event-type は、処理するイベントのクラスを指定します。このイベント ハンドラは event-type から継承したイベントを処理します。すべての on スタイルで event-type を指定する必要があります。
- target-var は、目標グラフィック オブジェクトの変数を定義します。メソッドまたは目標のプロパティへのアクセスが必要な場合、target-var を使用します。
- target-type は、目標のクラスを指定します。これは省略できますが、target-var を指定するとより能率的です。実際の目標がこのクラスでなく、強制的にこのクラスにすることができない場合、ランタイム エラーが送信されます。
注意: ダイナミック イベント ハンドラを記述するときは、on 式が含まれているコンテキストで定義された任意の変数を参照することができます。
次の例は、ポインタが中に入って離れるとその色が変わる長方形を示します。
Frame にアタッチされたダイナミック イベント ハンドラが 2 つあり、目標
Frame の 背景を設定することにより色を変更します。このオプションを参照するには、イベント ハンドラが、その目標を表す変数 (
rect) を宣言する必要があります。
例:
on 式で目標変数を宣言する |
|
{Frame
width=100pt,
height=50pt,
background = "orange",
|| attach the first dynamic event handler
{on PointerEnter at rect:Frame do
set rect.background = "cyan"
},
|| attach the second dynamic event handler
{on PointerLeave at rect:Frame do
set rect.background = "magenta"
}
}
| |
以下のサンプルでは、
HBox には 2 つの
Frame が含まれています。変数
left と
right は、左右のFrameを識別します。左のフレームには、明示的にイベントハンドラがアタッチされており、PointerEnterとPointerLeaveのイベントに反応して、右のフレームの色を変えます。ターゲットは左フレームですが、イベント ハンドラは右のフレームの背景色を変化させます。
例:
明示的にダイナミック イベント ハンドラを追加する |
|
{value
let left =
{Frame
background = "orange",
width=100pt,
height=50pt
}
let right =
{Frame
background = "orange",
width=100pt,
height=50pt
}
let my-hbox =
{spaced-hbox
left,
right
}
|| attach first event handler to left frame
{left.add-event-handler
{on PointerEnter do
set right.background = "aqua"
}
}
|| attach second event handler to left frame
{left.add-event-handler
{on PointerLeave do
set right.background = "magenta"
}
}
my-hbox
}
| |
以下のサンプルは、チェックボックスをtrueに設定した時にFrameにイベント ハンドラを追加し、チェックボックスをfalseに設定した時にイベント ハンドラを削除します。
例:
ダイナミック イベント ハンドラの削除 |
|
{value
let rectangle =
{Frame
width={make-elastic},
height=50pt,
background = {FillPattern.get-orange}
}
|| create a handler for PointerEnter event
let turn-me-aqua:EventHandler =
{on PointerEnter do
set rectangle.background = {FillPattern.get-aqua}
}
|| create a handler for PointerLeave event
let turn-me-magenta:EventHandler =
{on PointerLeave do
set rectangle.background = {FillPattern.get-magenta}
}
|| create a checkbutton that will alternately add or remove
|| the color changing event handlers
let checkbox:CheckButton =
{CheckButton
label = "Add color changers",
{on ValueChanged do
{if checkbox.value == true then
|| add color changers when the box is checked
{rectangle.add-event-handler turn-me-magenta}
{rectangle.add-event-handler turn-me-aqua}
else
|| remove color changers when it is unchecked
{rectangle.remove-event-handler turn-me-magenta}
{rectangle.remove-event-handler turn-me-aqua}
}
}
}
{VBox
checkbox,
rectangle
}
}
| |
イベントの処理とその動作の変更方法についてより深く理解するには、
Event および
EventTarget クラスについて理解すると共に、これらのクラスおよびその主要なサブクラスで利用できるメソッドの種類について知っておく必要があります。
イベント クラス階層の一部の詳細を次に示します。最もよく使用されるイベント クラスは、グラフィカル ユーザー インターフェイス関連のイベントを含む
GuiEvent、そのサブクラス
GuiWindowEvent、およびそのサブクラス
GuiInputEvent (マウスやキーボード イベントのすべてを含む)です。これらは、残りの章の主要点となります。
イベントはグラフィカル インターフェイスと通常関連していますが、必ずしもそうではありません。I/O イベントやソケット イベントだけでなく、タイマー イベントも含まれます。GUI イベントの詳細については、「
GUI およびウィンドウ イベント」のセクションを参照してください。
Copyright © 1998-2019 SCSK Corporation.
All rights reserved.
Curl, the Curl logo, Surge, and the Surge logo are trademarks of SCSK Corporation.
that are registered in the United States. Surge
Lab, the Surge Lab logo, and the Surge Lab Visual Layout Editor (VLE)
logo are trademarks of SCSK Corporation.