カテゴリー別アーカイブ: イベント

マルチタッチとジェスチャーAPI

 ※v8.0からサポートされました。

マルチタッチとジェスチャー イベントを制御するAPIが追加されました。

ジェスチャーイベントの種類として、

 Windowsでは、rotate、magnify、tap

 mac環境では、rotate、magnify、swipe

があります。


マルチタッチがお手元にある方: http://developers.curlap.com/curl/v8/touch/gesture.curl

 実際にその操作をしてみると、イベント名が出力されるサンプルです。
以下は、上記サンプルを用いて撮影したものです。

rotateのサンプル:http://developers.curlap.com/curl/v8/touch/rat.avi

magnifyのサンプル:http://developers.curlap.com/curl/v8/touch/mag.avi

tapのサンプル:http://developers.curlap.com/curl/v8/touch/tap.avi

 

 

Domainを使ったバリデーション機能の拡張

複雑な入力チェックを実装したい場合、ドメインをカスタマイズすることにより簡単に入力チェックを実装することが出来ます。

まずは下記のサンプルソースをご覧ください。このサンプルでは、StandardIntDomainを拡張して最小値、最大値、許容値チェックを実装しています。

{curl 6.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

|| ///////////////////////////////////////////////////////////////
|| カスタマイズしてvalidateのメッセージを変更したint型のドメイン
|| ///////////////////////////////////////////////////////////////

{define-class public CustomIntDomain {inherits StandardIntDomain}

  {constructor public {default
                          default-value:any = 0,
                          min-allowable:any = null,
                          max-allowable:any = null,
                          allowable-values:#{Array-of int} = null
                      }

    {construct-super
        default-value = default-value,
        min-allowable = min-allowable,
        max-allowable = max-allowable,
        allowable-values = allowable-values
    }
   
  }

  || /////////////////////////////////////////////////
  || メッセージ変更のためメソッドを拡張します。
  || /////////////////////////////////////////////////
  {method public {validate x:any}:#ValidationException

    ||最小値チェック(min-allowableが指定されていない場合は無視)
    {if-non-null min-val:any = self.min-allowable
     then
        let min:int = min-val asa int

        {if min > x asa int
         then
            ||最小値エラーの場合はValidationExceptionを返却
            {return
                {ValidationException
                    {format “%d未満の値を指定することは出来ません。”,min}
                }
            }
        }
    }

    ||最大値チェック(max-allowableが指定されていない場合は無視)
    {if-non-null max-val:any = self.max-allowable
     then
        let max:int = max-val asa int

        {if max < x asa int
         then
            ||最大値エラーの場合はValidationExceptionを返却
            {return
                {ValidationException
                    {format “%dよりも上の値を指定することは出来ません。”,max}
                }
            }
        }
    }

    ||範囲チェック(allowable-valuesが指定されていない場合は無視)
    {if-non-null data-sets:{Set-of any} = self.unsorted-allowable-values
     then
        {if not {data-sets.member? x}
         then
            ||範囲エラーの場合はValidationExceptionを返却
            {return
                {ValidationException
                    {format “%sは指定不可能な値です。”,x}
                }
            }
        }
    }

    {return {super.validate x}}    ||値が許容される場合はスーパークラスに処理を任せる

  }
}

||ドメインの定義
{let domain-for-validate:Domain =
    {CustomIntDomain
        min-allowable = 0,||最小値
        max-allowable = 100,||最大値
        allowable-values = {{Array-of int} 0,1,5,10,50}||指定可能な範囲値
    }
}

{let md1:MessageDisplay = {MessageDisplay}}

{TextField
    message-display = md1,
    {validate-with
        ||DomainValidatorにて使用するドメインを指定
        {DomainValidator domain-for-validate}
    }
}

{value md1}

このサンプルを実行すると、-1以下の値を入力した場合、100以上の値を入力した場合、allowable-valuesに含まれない値を入力した場合でそれぞれ異なるエラーメッセージが表示されます。

 int-validation.jpg

キー・イベントのハンドリング

キーボードからのキー・イベント(例えば、ファンクションキー、コントロールキー(Ctrl)、シフトキー(Shift)、Altキー、複合キー(Ctrl+Alt+AキーやShift+Aキーなど))が発生した場合に、何かの処理を実行する方法を説明します。

以下のサンプルでは、Ctrl+Aの操作が行われた場合に、ポップアップメッセージを表示いたします。

{value
        {Frame
            background = “red”, width = 3cm, height = 3cm,
            {on e:AttachEvent at v:Frame do
                def accel =
                    {KeyAccel
                        key-accel-string = “Ctrl+A”,
                        {on Action do
                            {popup-message “Press the Ctrl+A key.”}
                        }
                    }
               
                {if-non-null
                    focus-manager = {v.get-focus-manager}
                 then
                    {focus-manager.add-key-accel accel}
                }
            }
        }
}

まず、あるキーイベントが発行されたときの動作を定義するために、KeyAccelオブジェクトを引数にキーを文字列で指定します。これを表示している画面に登録するため(実際にはFocusManagerに登録することとなります)、Frameからget-focus-managerを利用して、FocusManagerを取得し、add-key-accelで作成したKeyAccelを追加します。複数キーを登録する場合もこれと同様に新しいKeyAccelを作成し、FocusManagerに追加していきます。

上記コードにより、Ctrl+Aを押下すると、「press the Ctrl+A key.」というメッセージボックスが表示されます。 

また、各コントロールのオプションでmnemonicというオプションがあり、これを用いることで簡単にキーイベントを設定することができます。ただし、これは”Alt+キー”しかできませんので注意してください。

 

 

バリデーションチェック

Validationとは、入力フィールドに入力された値が、一定の規則にしたがっているかをチェックする機能です。

Curlでは、このチェックをサーバ側ではなくクライアント側で行うことが可能です。全てのフォームを入力して[送信]ボタンを押したら間違いが・・・・というような状況を回避し、ユーザーエクスペリエンスの向上を実現することが可能です。

ここでは、個別フィールドに対してのValidationチェックを紹介していきます。

個別アイテムのValidationチェック

 まずは、色々な検証フィールドを見てみましょう

||数値検証
{let numeric-val:TextField =
    {TextField
        width = 3cm,
        {validate-with
            {NumericValidator},
            message = “年齢は数値で記入してください。”
        }
    }
}
||文字列検証
{let string-val:TextArea =
    {TextArea
        height = 3cm,
        width = 3cm,
        {validate-with
            {StringValidator max-chars=30},
            message = “コメントは30文字以内です。”
        }
    }
}

Curlでの検証機能には、validate-with プロシージャを使用します。その中で、Validatorクラスの引数を指定して、検証する法則を決定します。

上記の検証では、1つ目が数値(NumericValidator)、2つ目が文字列の検証(StringValidator)を行っています。文字列では、最小文字数(min-chars)や、最大文字数(max-chars)を設定することが可能です。

では、次の例を見てみましょう

||正規表現検証
{let phone-val:TextField =
    {TextField
        width = 3cm,
        {validate-with
            {RegExpValidator.from-ValidationPattern ValidationPattern.ja-phone-number},
            message = “電話番号が不正です。”,
            dialog-on-finished? = true
        }
    }
}

||正規表現検証2
{let md:MessageDisplay = {MessageDisplay}}
{let email-val:TextField =
    {TextField
        width = 3cm,
        message-display = md,
        {validate-with
            {RegExpValidator.from-ValidationPattern ValidationPattern.email-address},
            message = “メールアドレスが不正です。”
        }
    }
}
||ドメイン検証
{let md2:MessageDisplay = {MessageDisplay}}
{let domain-val:TextField =
    {TextField
        width = 3cm,
        message-display = md2,
        {validate-with
            {DomainValidator {StandardDateDomain}},
            message = “日付は、[日/月/西暦]の形式で記入してください。”
        }
    }
}

 

RegExpValidator クラスは、正規表現に基づいた検証を行います。今回はfrom-ValidationPatternコンストラクタを使用し、標準APIに組み込まれているValidationPattern という列挙型のクラスを使用しています。正規表現については、[逆引きリファレンス-データ操作-正規表現]をご覧ください。

DomainValidator クラスは、ドメイン(データ型から生成されます。例えばString,int,Time等の型を指します)の検証を行います。今回は日付のみの検証を行うために、StandardDateDomain クラスを使用しています。

以下のサンプルコードをダウンロードして、実際の挙動をお確かめください。(現状では、ValidationPatternのja-phone-numberに携帯電話の番号が対応していませんので、サンプルコードにて携帯電話用を検証可能な正規表現の列挙型を追加しておきました。)

ソースサンプル

色々な検証

関連ヘルプドキュメント

開発者ガイド-グラフィカル ユーザー インターフェイス – ガイアログとコントロール – コントロールにおけるデータ検証

APIリファレンス – CURL.GUI.CONTROL – VALIDATION – validate-with

APIリファレンス – CURL.GUI.CONTROL – VALIDATION – validate-dialog

APIリファレンス – CURL.GUI.CONTROL – VALIDATION – ValidationPattern

イベントの作成

Curlはユーザや他のプログラムが実行した操作(イベント)に対応して処理を行なうことができるイベントドリブン方式のプログラム言語です。一般的なイベントは「テキスト入力エリアに文字を入力する」時に発生するイベント(Curlの場合はValueChengedイベント)やボタンを押下するイベント(Curlの場合はActionイベント)また選択式のリストからデータを選択したときのイベント(Curlの場合はValueChangedイベント)があります。通常のWebのユーザーインタフェースのイベントは「ボタンを押下する」イベントによって処理が実行されるのみのものが多いのですが、その他にもユーザーの操作というものはさまざまになってきました。まさにこれらの操作に対応していることがリッチクライアントCurlの醍醐味です。

 

GUIコントロール部品の一般的なイベント

ボタンやリストボックスなどで発生する一般的なイベント処理のサンプルをご紹介します。以下にそれぞれのボタンを使用したサンプルソースを紹介します。

{curl 6.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}
{CommandButton
   label = “OK”,
   {on Action do
       {popup-message “ボタンが押されました!” }
   }
}
{CheckButton
   label = “Check for a kayak”,
   {on ValueFinished at cb:CheckButton do
       {if cb.value==true then
           {popup-message “チェックされました”}
        else
           {popup-message “チェックが解除されました”}
       }
   }
}
{VBox
   {text Select your favorite city},
   ||{italic Combo},
   {ComboBox
       width=3cm,
       “Milan”,
       “Moscow”,
       “Manchester”,
       value = “Milan”,
       {on ValueFinished at combo:ComboBox do
           {popup-message “Your favorite city is: ” & {value combo.value}}
       }
   },
   {italic Dropdown},
   {DropdownList
       width=3cm,
       “Milan”,
       “Moscow”,
       “Manchester”,
       value = “Moscow”,
       {on ValueFinished at drop:DropdownList do
           {popup-message “Your favorite city is: ” & {value drop.value}}
       }
   }
}

基本的なイベントの操作ははon構文を使用してダイナミックイベントハンドラを設定してイベントを処理します。
上記のサンプルを例に説明しますとCommandButtonやDropdownListオブジェクトの中に”{on Action do …}”や”{on ValueFinished do …}”という構文がありますように、”{on XXX do …}”でダイナミックイベントを設定できます。XXXの部分にはそれぞれイベントタイプを設定します。
CommandButtonの場合はActionクラスを指定していまして「押された時」に発生するイベントクラスです。”…”の部分にはイベントが発生した時の処理を記述します。Commandbuttonの例ですとボタンを押したときにポップアップで「ボタンが押されました。」と出力されます。

ポインタイベント

一般的なWebアプリケーションのGUIの処理は「押す」や「選択する」といったイベントのみの場合が多いですが、Curlはより複雑なユーザー操作のイベントを処理できます。
以下はマウスポインタの処理の例です。

{VBox
    height = 2in,
    width = 1in,
    background = “blue”,
    {on e:PointerPress at v:VBox do
        set v.background = “red”
        {e.consume}
    },
    {on e:PointerRelease at v:VBox do
        set v.background = “blue”
        {e.consume}
    }
}
{VBox
    height = 1in,
    width = 1in,
    background = “blue”,
    {on e:PointerEnter at v:VBox do
        {if e.shift? then
            set v.background = “red”
         else
            set v.background = “cyan”
        }
        set v.height = 2in
        {e.consume}
    },
    {on e:PointerLeave at v:VBox do
        set v.background = “blue”
        set v.height = 1in
        {e.consume}
    }
}

上記の例では2つのVBox(垂直方向に子オブジェクトをならべる箱)にダイナミックイベントを設定しています。
上のVBoxではポインタが「左クリックされた」ときと「左クリックを離した」ときのイベントを設定します。
下のVBoxではポインタが「VBoxに入った」ときと「出ていった」ときのイベントの設定にくわえて、「Shiftキーを押しながら入った」ときとそうでない時で処理を分けています。
このようにポインタの処理だけでも色々なイベントを処理することができ、またキーボード操作と組み合わせて処理することもできます。

キーイベント

キーボードの操作に対する処理もポインタイベントと同じように処理することができます。
以下はキーボードイベントのサンプルコードです。

{Frame
   width=2in,
   height=1in,
   background=”blue”,
   {on p:PointerPress at f:Frame do
       {f.request-key-focus}
       set f.background = “green”
       {p.consume}
   },
   {on kp:KeyPress at f:Frame do
       {if kp.shift? then
           set f.background = “red”
        else
           set f.background = “yellow”
       }
       {if kp.value == KeyPressValue.home then
           {popup-message “You pressed home”}}
   }
}

Frameに先ほどのポインタ操作のイベントにくわえ、”KeyPress”というイベントを使ってキーボード操作に対する処理を記述しています。
このサンプルはFrameにフォーカスがある状態のときに何かのキーを押すと黄色になり、またShiftキーを押しながら、任意のキーを押すと赤になります。最後のコードはHomeキーを押したときのイベント処理を設定しています。このように特定のキー入力に対してや、またショートカットキーでよくある”Ctrl+C”や”Ctrl+V”などの修飾キーとの連携イベントまでも制御できます。

 

ドラッグアンドドロップイベント

ドラッグアンドドロップイベントはまさにリッチクライアントでユーザーインタフェースを使うことの醍醐味です。
ドラッグアンドドロップを実現するのは難しいと思われがちですが、Curlの場合は他のイベント処理と同じようにドラッグアンドドロップイベントを操作することができます。
以下に簡単なドラッグアンドドロップのサンプルを紹介します。

drag-drop.jpg

{text 丸を四角エリアにドラッグしてください。}
{text CTRを押しながらドラッグするとコピーされます}

{HBox
    valign = “center”, width = 9cm,
    {EllipseGraphic
        width = 1cm, height = 1cm, dragee = {ImageDragee}},
    {Fill width = {make-elastic preferred-size = 10cm}},
    {VBox
        width = 1.5cm, height = 1.5cm, border-width = 1pt,
        border-color = {FillPattern.get-black},
        opaque-to-events? = true,
        {on e:DragOver do
            {e.will-accept-drop?
                {proc
                    {a:Type,
                     b:Distance,
                     c:Distance,
                     d:#DragEffect
                    }:DragEffect
                    {if {d.has-effect? “copy”} then
                        {return drag-effect-copy}
                     else
                        {return drag-effect-move}
                    }
                }
            }
        },
        {on e:Drop at vb:VBox do
            {e.accept-drop
                {proc
                    {w:any,
                     x:Distance,
                     y:Distance,
                     z:#DragEffect
                    }:DropResult

                    {if {z.has-effect? “copy”} then
                        {return
                            {DropResultCopy
                                action =
                                    {proc {}:void
                                        {vb.add {w.clone-appearance}}
                                    }
                            }
                        }
                     else
                        {return
                            {DropResultMove
                                action =
                                    {proc {}:void
                                        {vb.add w}
                                    }
} } } } } } } }

ソースサンプル

関連ヘルプドキュメント

Curl開発者ガイド-グラフィカルユーザーインタフェース-イベント
Curl開発者ガイド-グラフィカルユーザーインタフェース-ドラッグアンドドロップ