「オープンソース – Curl External Library」カテゴリーアーカイブ

オープンソース – Curl External Library 概要

Curl External LibraryはCurl言語のための外部ライブラリを集めたオープンソースで、http://sourceforge.net/projects/curl-ext/より無償でダウンロードできます。

尚、利用にあたっては、 developers.curlap.com に特権を設定しないと動作しないコンポーネントもあります。

ここではいつくかのコンポーネントを紹介します。以下のコンテンツの画像をクリックすると各機能の詳細ページへ移動します。

 

 


アニメーション画面遷移

 transition-frame.png

アニメーションを用いた画面遷移や、ポップアップウィンドウを実現します。 

 


ガントチャート

gantt-demo.jpg

ガントチャートが作成できます。

 


ワークシート

worksheet2.jpg

Worksheetは、Excelのようにスプレッドシート風のGUIコンポーネントです。
以下のような特徴があります。

・式を埋め込み、セルの値を入力値として計算することができます。
・値の入力のために標準GUIコントロールをセルに埋め込んで使用することができます。
・フォームやRecordGridを埋め込んでRecordSetデータを表示することができます。

 


ジオグラフィックAPI

geo-sample1.gif

シェープファイル (Shapefile) を読み込んで表示させる API(GeoGraphicAPI) が用意されています。

 


ローディング・アニメーション

sample-splash.jpg

ローディングや処理待ちのためのアニメーションを用いたスプラッシュ・スクリーンGUIコントロールです。

 


バックグラウンドタスク

backgroundtaskdemo.jpg

マルチスレッドプログラミングを実現します。

 

 


 

計算レコードセット

calcrec.jpg

CalculatedRecordSetは、LocalRecordGridにセル間で計算する機能を付加します。セルの値が変更されると、値を参照しているセルの値も自動的に再計算されます。

 


自動テスト・フレームワーク

autotestframework.jpg

Autotest FrameworkはGuiコントロールのテストを自動化するフレームワークです。以下のような特徴があります。

・シンプルなスクリプトを書くだけで、単一のコントロール、あるいはその他のGraphicのテストができます。
・一つのテストアプレットで複数のテストを実行でき、実行したテストとその結果を表示します。
・イベントを発生させることができ、その結果が期待通りかどうかチェックできます。

 


ツリーグリッド

tree-grid.jpg

1番目のカラムにツリーを持つRecordGrid です。

 


オートコンプリート

auto-complete.jpg

自動補完機能は、一般的なWebサイトでも実現されていますが、Curlでも実現することができます。サーバサイドに簡単なプログラムを配置する必要はありますが クライアント側の自動補完の実装をCurlのみで実現可能ということは強みです。

 


カスタム・タイトルバー

sample-titledview.jpg

TitledViewは、スキンが適用されたタイトルバーです。 普通のViewはプラットホームのネイティブの外観が使用されますが、 TitledView は概観がカスタマイズされた独立アプレットです。これにより、タイトルバーをプラットホームの制御下から解放することができ、Curl側にて制御可能です。

 


ポップアップ・バルーン

balloon-view.jpg

The BalloonView APIは、アプレット内のいくつかのグラフィックに対して角が丸い小さいなウィンドウを持つポインターとして使用されます。ポップアップのイメージですので、カレンダーコントロールと組み合わせることにより、簡単なスケジュールツールを作成することもできます。

 


ファイル操作API

fileapp.jpg

FileAppは一度に一つファイルを編集する標準的Curlアプリケーションのひな形となる抽象クラスです。標準的なファイルメニューを提供します。


 

 

Curl External Library 利用方法

Curl External Libraryをプロジェクトで利用するには、以下の手順でデリゲートする必要があります。

Curl External Libraryをダウンロードし、展開する。

【CDEの場合】

  • ElipseのメニューバーのWindow->Preferencesを選択して[Preferences]ダイアログを開く。
  • Curl->インストール済みのライブラリを選択
  • インストールボタンを押して展開したディレクトリのCOM.CURL.EXT-V0.6.1/manifest.mcurlを選択し、開くボタンを押下。

※APIドキュメントも同時にインストールする場合はCOM.CURL.EXT-V0.6.1-doc/manifest.mcurlを選択してください。

  • 後はプロジェクトエクスプローラーからプロジェクトを右クリックして「Curlマニフェスト」->「ライブラリの管理」で「COM.CURL.EXT」にチェックを入れれば各プロジェクトで使用できます。

【Classic IDEの場合】

  • Curl IDEで、メニューからプロジェクト→デリゲート先の追加を選択
  • 展開したディレクトリのCOM.CURL.EXT-V0.6.1/manifest.mcurlを選択し、開くボタンを押下。

これで、Curl External LibraryのAPIが利用できます。(もちろん、importはしてください。)

Curl External Library APIリファレンスのインストール

APIリファレンスをCurlのドキュメントに追加するには、以下の手順で実施します。

【CDEの場合】

ライブラリのインストールをすることでAPIリファレンスも同時にインストールされます。くわしくは以下を参照ください。

Curl External Library 利用方法

 

【Classic IDEの場合】

  • Curl External Library をダウンロードします。(CURL-EXT-V0.6.1.zipをダウンロードしてください。)
  • Curl IDEを起動
  • メニューからヘルプ→ドキュメンテーションのインストールを選択
  • インストールボタンを押下し、ダウンロードしたファイルの展開後のディレクトリから、COM.CURL.EXT-V0.6-doc/manifest.mcurlを選択します。
  • ダイアログの一覧にCOM.CURL.EXTが追加されます。

    これで、APIリファレンスを利用することが可能となります。
    (Curl ドキュメント・ビューワを開き、目次の一覧からCOM.CURL.EXTを参照)

     

    ジオグラフィックAPI

    Curl External Libraries の中にシェープファイル (Shapefile) を読み込んで表示させる API(GeoGraphicAPI) が用意されています。

    シェープファイルとは

    シェープファイル (Shapefile) は、地理情報システム (GIS)で標準的に用いられるファイル形式。

    米国ESRI社のGIS標準データフォーマット形式である。 シェープファイルは3つのファイルからなり、属性情報は DBase 形式に収められる。 このデータ形式は、多くのデータ形式の中でも互換性が高く、事実上の業界標準であり、多くの企業が発売しているGISシステムで利用することができる。  データ変換ツールなどによって、Google Earthで用いられているKML形式にも出力が可能。

     

    Wikipedia – シェープファイル

    http://ja.wikipedia.org/wiki/シェープファイル より引用

     

    また、シェープファイルは以下の構成となっており、

    • .shp ファイル ・・・ 図形情報が保存されている
    • .dbf ファイル ・・・ 属性情報が保存されている
    • .shx ファイル ・・・ .shpの図形情報と.dbfの属性情報の対応関係が保存されている
    個別の各ファイルだけで利用することはできません。

    シェープファイルは多くの GIS ソフトウェア(※1)で利用が可能であり、GIS 製品の標準フォーマットとなっています。

     

    ※1 GIS ・・・ 地理情報システム(GIS:Geographic Information System)

    地理的位置を手がかりに、位置に関する情報を持ったデータ(空間データ)を総合的に管理・加工し、視覚的に表示し、高度な分析や迅速な判断を可能にする技術

    GISとは・・・ | 国土地理院

    http://www.gsi.go.jp/GIS/whatisgis.html

     

    GeoGraphicAPI の利点

    シェープファイルをCurlアプリケーションを読み込むことで、様々な図形情報にイベント処理やグラフィカルな処理を行うことが可能となります。

    これは、日本の市町村単位の属性情報を持ったシェープファイルをGeoGraphicAPIを使用してCurlアプリケーションで読み込んだものです。

    Curlアプリケーションの内部では読み込んだシェープファイルの図形情報をShapeオブジェクトとして保持し、そのShapeオブジェクト一つ一つに属性情報のデータが保持されています。

    CurlのShapeオブジェクトによってCurlアプリケーション内で表現されるため、このShapeオブジェクトにたいし、PointerEnter、PointerPress等のイベントを設定することができ、ユーザのアクションに対して様々な処理を設定することが可能となります。

    例えば、日本地図の上でマウスを動かすだけで、マウスポインタの下にある市町村の名前、人口、郵便番号などの情報をツールチップなどによって表示させることも可能となります。

    また、複数のシェープファイルを使用し、重ね合わせることで表現豊かに表示することができます。

    例えば、日本地図のシェープファイルと、日本の鉄道の路線図のシェープファイルを読み込み、重ね合わせるだけで日本全土の鉄道網が表示できたり、日本地図と公示地価データを読み込み、地価の変動率を色で表現することで視覚的にデータを理解することも可能となります。

    GeoGraphicAPI の使い方

    GeoGraphicAPIを使うには、以下のパッケージとクラスの使い方を理解すれば簡単に利用することが出来ます。

    • COM.CURL.EXT.GEOGRAPHIC パッケージ
    • MapLayerManager クラス
    • SingleMapLayer クラス

    COM.CURL.EXT.GEOGRAPHIC パッケージは使用する箇所で import しパッケージ内のクラスやプロシージャを利用できるようにします。

    MapLayerManager クラスはこのシェープファイルを読み込んでCurl内で表示する機能全体を管理するクラスです。

    SingleMapLayer クラスは一つのシェープファイルの読み込み、データの保持、表示を管理するクラスです。

    複数のシェープファイルをCurlアプリケーション内で表示する場合は、複数のSingleMapLayerオブジェクトをMayLayerManagerオブジェクトが管理していることとなります。

     

    SingleMapLayer をインスタンス化する際のコンストラクタの引数は以下のようになります。

        SingleMapLayer.default
            shape-file-name:String,                拡張子をのぞいたシェープファイルの名前
            shape-file-dir:Url,                         シェープファイルが置いてあるディレクトリ
            region-color:FillPattern = "white",    表示する色
            ellipse-radius:Distance = 1pt,         表示するシェープが点の場合の大きき
            ...

     

    MapLayerManager をインスタンス化する場合は、以下のようにコンストラクタ引数にSingleMapLayerオブジェクトを渡してください。

        {MapLayerManager single-map-layer}

     

    また、表示するシェープファイルを追加する場合は、MapLayerManager.append-layer メソッドを使用して下さい。

    画面へ表示する場合は、以下のようにMapLayerManagerクラスの持つMapDisplay.canvasオブジェクトを表示してください。

        {self.add self.manager.map-display.canvas,
            replace? = true
        }

    GeoGraphicAPI を使ったサンプル

    geo-sample2.gif

    国土交通省国土計画局では、国土計画の策定や推進の支援のために、国土に関する様々な情報を整備、数値化したデータを公開されています。例えば、日本の行政地域、海岸線、鉄道、地価公示情報など様々なデータが公開されています。

    この中に日本の発電所に関するデータが公開されていますので、これを用いて日本地図と重ね合わせて表示しています。また、シェープファイルの属性情報に保存されている、各発電所のデータも見ることが出来ます。

     

    国土数値情報ダウンロードサービス

    http://nlftp.mlit.go.jp/ksj/index.html

    GeoGraphicAPI – 発電所一覧

    http://developers.curlap.com/curl/curl-ext/geo-sample/start.curl

     

    オートコンプリート

    AutoCompleteを紹介します。

    自動補完機能は、一般的なWebサイトでも実現されていますが、CurlでもAutocompleteTextFieldクラスを利用することで、簡単に実現することができます。

    sample-autocomplete.jpg

    使い方

    サーバサイドに簡単なスクリプト等を用意する必要があります。詳細は、 サンプルに記載しております。ここでは、Curl側の使い方を紹介します。

    {AutocompleteTextField
       {RandomCompletionProvider}
    }

    AutocompleteTextFieldは、TextFieldを継承して作成されたクラスです。

    引数:provider:AutocompleteProviderには、オンデマンドでデータを提供するためのクラスを指定します。例えば以下のようにAutocompleteProviderを継承して、refreshメソッドをオーバーライドします。

    {define-class public open RandomCompletionProvider
      {inherits AutocompleteProvider}

      field public rng:LinearRandom
      field public digits:int

      {constructor public {default
                              max-results:int = 10,
                              digits:int = 6
                          }

        {construct-super max-results}
        set self.digits = digits
        set self.rng =
            {LinearRandom seed = ({DateTime}.info.fraction * 10000) asa int}
      }

      {method public open {refresh acf:AutocompleteMixin}:void
        def tf = acf.text-field
        def s = tf.value
        let items:StringArray = {StringArray}
        def result-count = {max 10, self.max-results}
        {if s.size < self.digits then
            def n = self.digits – s.size
            let a:int = 1
            let b:int = {pow 10.0, n} asa int
            let f:String = {format “%%s%%0%dd”, n}
            {for i = 0 below result-count do
                {items.append {format f, s, {self.rng.next-in-range a, b – 1}}}
            }
        }
        {acf.populate-from-strings items}
      }
    }

    この例では、「http://developers.curlap.com/curl/curl-ext/hp/php/words-containing.php?value=%s&max=%s」にリクエストを送り、結果をドロップダウンで表示します。

    サンプル

    以下のリンクにて、サンプルプを確認することができます。

    http://developers.curlap.com/curl/curl-ext/hp/curlext-overview_autocomplete_textfields.curl

    このサンプルでは、サーバサイドには、以下のようなphpソースと、TXTファイルを配置しています。

        ————【phpソース】——————————————————
            $req_value = $_GET[‘value’];
        $vals = file(“words.txt”);
        $count = count($vals);
        $output = “”;
        for ($i = 0; $i < $count; $i++) {
                                            $pos = stripos($vals[$i], $req_value);
                                            if ($pos === FALSE) {
                                                                    // Skip it.
                                                                } else {
                                                                           if ($pos >= 0) {
                                                                                              $output .= “$vals[$i]”;
                                                                                          }
                                                                       }
                                        }
        echo “$output”;
        ?>
        ————【TXTファイル】——————————————————
          http://developers.curlap.com/curl/curl-ext/hp/php/words.txt

     

    また、Google Suggestion APIとの連携はこちらを参照ください。

     

    オートコンプリートとGoogle Suggestion APIを組合わせる

    Curl External Library のオートコンプリート機能にGoogle Suggestion APIを組み合わせたサンプルです。

    まずは、Google Suggestionからデータを取得する方法です。以下はキーワードを入力すると候補文字のリストを返してくれます。

    {define-proc {find-google-suggestions
                     word:String,
                     host-locale:Locale = {get-host-locale}
                 }:{Array-of String}
        def query =
            “http://suggestqueries.google.com/complete/search?hl=%s&qu=%s&json=t
        def suggestions = {{Array-of String}}
        def qu = {url-encode-string word}
        {with-open-streams
            tis = {read-open {url {format query, host-locale.name, qu}}}
         do
            def results = {JsonValue-parse tis} asa JsonArray
            {for v in results[1] asa JsonArray do
                {suggestions.append v asa String}
            }
        }
        {return suggestions}
    }

    次にAutocompleteTextFieldで、データの候補を表示するためのAutocompleteProviderクラスを作成します。例えば以下のようにGoogleSuggestionProviderクラスをAutocompleteProviderを継承して作成します。

     

    {define-class public open GoogleSuggestionProvider
      {inherits AutocompleteProvider}

      {method public open {refresh acf:AutocompleteMixin}:void
        def word = acf.text-field.value
        {if word.size > 0 then
            {acf.populate-from-strings
                {find-google-suggestions word}
            }
        }
      }

      {constructor public {default max-results:int = 10}
        {construct-super max-results}
      }
    }

    最後にAutocompleteTextFieldを利用して、データを表示させます。

    {AutocompleteTextField
        {GoogleSuggestionProvider},
        {on FocusIn at acf:AutocompleteTextField do
            {acf.provider.refresh acf}
        }
    }

     

    ワークシート

    Worksheetは、Excelのようにスプレッドシート風のGUIコンポーネントです。
    以下のような特徴があります。

    ・式を埋め込み、セルの値を入力値として計算することができます。
    ・値の入力のために標準GUIコントロールをセルに埋め込んで使用することができます。
    ・フォームやRecordGridを埋め込んでRecordSetデータを表示することができます。

     

     

    Worksheetクラス

    Worksheetクラスのコンストラクタに以下のようなプロシージャがセットできます。

    value-cell 値を表示するセル
    input-cell 編集、入力するセル
    currency-cell 通貨を含むセル
    formula-cell 式を含むセル

    これらはCellSpecオブジェクトを戻り値として返し、セルの表示を制御します。

    サンプル

    以下はWorksheetでごく簡単な計算を行うサンプルです。

    worksheet1.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/worksheetdemo1.curl

    使い方

    このWorksheetは以下のようなコードで作成されています。

    {Worksheet 4, 2,
        row = 0, col = 0, “A”, {input-cell 0.0},
        row = 1, col = 0, “B”, {input-cell 0.0},
        row = 2, col = 0, “C”, {input-cell 0.0},
        row = 3, col = 0, “A + B + C”,
        {formula-cell
            {proc {dest:DataRef, a:DataRef, b:DataRef, c:DataRef}:void
                 set dest.value = a.as-double + b.as-double + c.as-double
            },
            {RelativeCellRef -3, 0},
            {RelativeCellRef -2, 0},
            {RelativeCellRef -1, 0}
        }
    }

    ここでは、ワークシートのコンストラクタの中で
    4行2列のワークシートのセルを以下のように一つずつ設定しています。

    1行1列目 “A”,
    1行2列目 {input-cell 0.0}
    2行1列目 “B”, 
    2行2列目 {input-cell 0.0},
    3行1列目 “C”, 
    3行2列目 {input-cell 0.0},
    4行1列目 “A + B + C”,

    そして4行2列目(“A + B + C”の次)のセルとして記述されている
    formula-cellプロシージャが数式のセルを設定しています。

    formula-cellの第一引数となっているプロシージャ定義が、このセルが表示する値を決める数式です。引数として与えられたaセルの値とbセルの値を加算してdestセルにセットしています。destセルは数式を設定しているこのセル(row = 2,col = 0)、aセルはこのセルの3行上のセル、bセルは2行上のセル、cセルは3行上です。aとbをこれらのセルに紐付けているのが続く三行のRelativeCellRefオブジェクトです。

    {RelativeCellRef -3, 0}が3行上、
    {RelativeCellRef -2, 0}が2行上、
    {RelativeCellRef -1, 0}が1行上のセルを指し、

    この順に書くことでaが3行上、bが2行上、cが1行上のセルを指すことを示しています。
    destセルはプログラマが明示的に設定する必要はなく、内部で自動的にこのセルを指します。

    ここで、

    {proc {dest:DataRef, a:DataRef, b:DataRef}:void
        set dest.value = a.as-double + b.as-double
    }

    の部分は Formula.sumに置き換えても同じ動作をします。

    Formulaクラスには以下のような基本的な演算プロシージャが組み込みで用意されています。

    copy 一つの引数を取り、ターゲットセルにそのセルの内容を表示します。
    add 二つの引数を取り、ターゲットセルにその値の和を表示します
    subtract 二つの引数を取り、ターゲットセルにその値の差を表示します
    multiply 二つの引数を取り、ターゲットセルにその値の積を表示します
    divide 二つの引数を取り、ターゲットセルにその値の商を表示します
    sum すべての引数の合計をターゲットセルに表示します
    product すべての引数をかけ合わせた値をターゲットセルに表示します
    concat すべての引数を連結した値をターゲットセルに表示します
    count すべて引数の数をターゲットセルに表示します

    上記サンプルをFormula.sumプロシージャで書き換えると次のようになります。

    {Worksheet 4, 2,
        row = 0, col = 0, “A”, {input-cell 0.0},
        row = 1, col = 0, “B”, {input-cell 0.0},
        row = 2, col = 0, “C”, {input-cell 0.0},
        row = 3, col = 0, “A + B + C”,
        {formula-cell
             Formula.sum,
             {RelativeRangeRef 3, 1, row = -3}
        }
    }

    こちらの場合は、数式プロシージャの引数の指定に、
    一つずつセルを参照するRelativeCellRefの代わりに
    RelativeRangeRefが使われています。
    RelativeRangeRefは複数のセルを含む矩形領域を参照します。

    コンストラクタ引数は以下のようになっています。

    RelativeRangeRef.default
        rows:int ターゲットセルの行番号に加えるオフセット値
        cols:int ターゲットセルの列番号に加えるオフセット値
        row:int 領域に含まれる行の数(デフォルト:0)
        col:int 領域に含まれる列の数(デフォルト:0)

    上のコードでは、3行1列の矩形領域を、ターゲットセルの3行上のセルから定義しています。

    カスタムセルエディタ

    セルの値の編集には、普通TextFieldが使われますが(日付の場合はDateField)、
    ユーザがそのコントロールを指定することができます。
    各セルは以下の三つのパラメータを取ります。

    editable?:bool ユーザによる編集の可否(デフォルト:false)
    locked?:bool セルの編集可否状態を固定表示するかどうかの設定(デフォルト:false)
    ui-spec:any セルの値の編集/表示方法の設定(デフォルト: null)

    このui-specへの設定によってコントロールを指定することができます。

    ValueControlを指定した場合には、WorksheetがValueFinishedイベントを
    自動的に認識してセルを更新し再計算を行います。

    サンプル

    以下はSliderコントロールを埋め込んだサンプルです。

    worksheet2.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/worksheetdemo2.curl

    使い方

    以下のように、ui-spec としてSliderオブジェクトを設定します。

    {Worksheet 4, 3, {widths 18pt, 2in},
         row = 1, col = 1, 
         row-height = 48pt, {input-cell 4, domain = int, ui-spec = {Slider}},
         {formula-cell Formula.copy, {RelativeCellRef 0, -1}},    
         …
    }

    EmbeddedRecordGridの埋め込み

    WorksheetにはRecordGridを埋め込むことができます。

    サンプル

    以下は、セルに埋め込んだRecordグリッドでRecordSetを表示するサンプルです。

    worksheet3.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/worksheetdemo3.curl

    使い方

    EmbeddedRecordGridコントロールをセルに埋め込んでいます。
    RecordGridの列数+1となる値(ここでは5)をcolspanにセットすると
    グリッドの一列にワークシートの一列が自動的に割り当てられ、
    ワークシートのカラム幅を調整するとグリッドのカラム幅も連動して変更できます。

    EmbeddedRecordGridをインスタンス化する際のコンストラクタ引数は以下のようになります。

    EmbeddedRecordGrid.default
       worksheet:#Worksheet                  ||このEmbeddedRecordGridと関連付けられるWorksheet(デフォルト:null)
       record-source:#RecordSet               ||ここから取り出される各レコードがグリッドを生成します(デフォルト:null)
       sort:#RecordSort                           ||表示データのソート順定義(デフォルト:null)
       filter:#RecordFilter                         ||データの一部を表示するためのフィルタ(デフォルト:null)
       key-spec:any                                ||RecordGrid.key-specの初期値を与える(デフォルト:null)
       header-options:RecordGridRowOptions  ||ヘッダのためのグラフィックオプション(デフォルト:{RecordGridRowOptions})
       ui-object:#RecordGridUI                 ||代替UIオブジェクト(デフォルト:{ProtoSkinnableRecordGridUI})

    EmbeddedRecordFormの埋め込み

    WorksheetにはRecordFormを埋め込むことができます。

    サンプル

    次のサンプルは、RecordSetをフォームで表現することで実現したToDoリストです。
    EmbeddedRecordFormが埋め込まれています。

    worksheet4.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/worksheetdemo4.curl

    使い方

    EmbeddedRecordFormをインスタンス化する際のコンストラクタ引数は以下のようになります。

    EmbeddedRecordForm.default
       data-source:RecordSetDataSource            ||ここから取り出される各レコードがフォームを生成します。
       id-field:String                                       ||キーとなるフィールド名(デフォルト:”id”)。
       worksheet:#Worksheet                          ||このEmbeddedRecordFormWorksheetが属しているWorksheet(デフォルト:null)。
       sort:#RecordSort                                  ||適用するソート(デフォルト:null)。
       filter:#RecordFilter                                ||適用するフィルタ(デフォルト:null)。

    FieldSpecクラスが、レコードの各フィールドの値を表示、編集するためのセルとなります。
    コンストラクタの引数は以下のようになります。

    FieldSpec.default
       field-name:String             ||フィールド名
       rowspan:int                     ||行の範囲(デフォルト:1)
       colspan:int                      ||列の範囲(デフォルト:1)
       editable?:bool                 ||ユーザによる編集の可否(デフォルト:false)
       locked?:bool                   ||セルの編集可否状態を固定表示するかどうかの設定(デフォルト:false)
       ui-spec:any                    ||セルの値の編集/表示方法の設定(デフォルト: null)
       …

     

    ポップアップ・バルーン

    BalloonViewAPIの使い方について紹介します。

    The BalloonView APIは、アプレット内のいくつかのグラフィックに対して角が丸い小さいなウィンドウを持つポインターとして使用されます。ポップアップのイメージですので、カレンダーコントロールと組み合わせることにより、簡単なスケジュールツールを作成することもできます。

    sample-balloon.jpg

    BalloonViewAPIは、Viewクラスを継承して作成されています。使い方は、Viewクラスと似ています。

    {BalloonView
       content:Graphic,     – Dialogなどバルーンの中身を指定します。
       owner:Graphic,      – 遷移元オブジェクトを指定します。
       x:Distance,         – ポインタの座標を指定します。PointerReleaseイベント時の座標を指定するとよいでしょう。
       y:Distance          – ポインタの座標を指定します。PointerReleaseイベント時の座標を指定するとよいでしょう。
    }

     

    サンプル

    以下のリンクにて、サンプルを確認することができます。

    http://developers.curlap.com/curl/curl-ext/hp/curlext-overview_baloonview.curl

     

    カスタム・タイトルバー

    TitledViewを紹介します。

    TitledViewは、スキンが適用されたタイトルバーです。 普通のViewはプラットホームのネイティブの外観が使用されますが、 TitledView は概観がカスタマイズされた独立アプレットです。これにより、タイトルバーをプラットホームの制御下から解放することができ、Curl側にて制御可能です。

    このようなカスタマイズされたタイトルビューを作成することができます。

    sample-titledview.jpg

     

    使い方

    TitledViewはViewクラスを継承して作成されたクラスです。

    {TitledView
      title = “Sample TitledView”
    }

    と記載するだけで、簡単なタイトルビューを確認することができます。

    サンプル

    以下のリンクにて、サンプルを確認することができます。

    http://developers.curlap.com/curl/curl-ext/hp/curlext-overview_titledview.curl

     

    ツリーグリッド

    TreeGridを紹介します。

    1番目のカラムにツリーを持つRecordGrid です。

    sample-treegrid.jpg

    使い方

    TreeGridは、RecordGridを継承して作成されたクラスです。

    {TreeGrid
      {RecordSetTreeModel.from-Url
        {url http://developers.curlap.com/curl/curl-ext/hp/t-treegrid_sample.csv},
        {RecordField “title”, domain = String},
        {RecordField “notes”, domain = String}
      },
      {RecordGridColumn
         “title”
      },
      {RecordGridColumn
        “notes”
      }
    }

    RecordGridと似たような使い方なのですが、特徴は、引数に model:RecordSetTreeModelを指定することです。
    この例ではCSVファイルを指定していますが、ツリーモデルのデータが格納されています。

    サンプル

    以下のリンクにて、サンプルを確認することができます。

    http://developers.curlap.com/curl/curl-ext/hp/curlext-overview_treegrid_v1.curl

    http://developers.curlap.com/curl/curl-ext/hp/curlext-overview_treegrid_v2.curl 

    ローディング・アニメーション

    TranslucentSplashScreenを紹介します。

    下図のように、ローディングや処理待ちのためのアニメーションを用いたスプラッシュ・スクリーンGUIコントロールです。

    sample-splash.jpg

     

    使い方

    このAPIを使うには、いくつかの手順を踏む必要があります。

    ||–初期処理
    {TranslucentSplashScreen.setup
       splash-applet-url =
         {string-url
            ||–アニメーション用のパラメータを指定することでカスタマイズできます。
            {CircleAnimation.make-splash-subapplet-ource}
         }
    }

    ||–タイトルの設定
    {TranslucentSplashScreen.set-title “Loading data…”, color = “#0000c0”, font-size = 14pt}
    {TranslucentSplashScreen.set-progress-bar max = 49}

    || アニメーションのためのフェイク処理
    {for i = 0 below 50 do
       {sleep 60ms}
       {TranslucentSplashScreen.set-progress-bar-value i}
       {dispatch-events false}
    }
    || SplashScreenの終了処理
    {TranslucentSplashScreen.destroy}

    サンプル

    以下のリンクにて、サンプルプログラムを確認することができます。

    http://developers.curlap.com/curl/curl-ext/hp/docs/samples/sample-splash-animation.curl

     

    自動テスト・フレームワーク

    Autotest FrameworkはGuiコントロールのテストを自動化するフレームワークです。以下のような特徴があります。

    ・シンプルなスクリプトを書くだけで、単一のコントロール、あるいはその他のGraphicのテストができます。
    ・一つのテストアプレットで複数のテストを実行でき、実行したテストとその結果を表示します。
    ・イベントを発生させることができ、その結果が期待通りかどうかチェックできます。

    このAPIの使用およびサンプルの起動はCDEまたはIDEのインストールが
    必要になります。以下よりダウンロードしてください。
    http://curlap.com/download/ide/index.html

    サンプル

    autotestframework.jpg


    http://developers.curlap.com/curl/curl-ext/hp2/checkbuttontests.curl

    このサンプルはチェックボックスの動作をテストします。
    背景色がテストのステータスを表します。未実行のテストはグレー、成功したテストは緑、失敗したテストはピンクになります。

    テスト1

    • チェックボックスコントロールの、左から0mm,上から2mmの点をマウスで左クリックして、以下の項目を確認する。
      1.ValueChangedEvent,ValueFinishedEventが発生する。
      2.値が”CB1″となる。
    • この状態から、左から2mm,上から0mmの点をマウスで左クリックして、以下の項目を確認する。
      1.ValueChangedEvent,ValueFinishedEventが発生する。
      2.値がnullとなる。

    テスト2

    • チェックボックスコントロールにフォーカスがあり、valueプロパティがfalseの状態でキーボードからAlt+Tを押下して、以下の項目を確認する。
      1.valueプロパティがtrueとなる。
    • この状態でキーボードからスペースキーを押下する。
      1.valueプロパティがtrueとなる。

    使い方

    テストを定義して、GuiTest.setupを呼びます。
    テストはGuiTestクラスのオブジェクトで表現します。これは 1.ターゲットとなるオブジェクト、2.テストの簡単な説明、3.テストステップの三つの部分から成ります。テストのステップはUIクラスのインスタンスで表現します。ここでは以下のようなものが使用されています。

    || valueプロパティの値がfalseであることを確認する。
    {UI.check-property “value”, false}   
    || マウスで、コントロールの左から1cm,上から0mmのポイントを左クリックする。
    {UI.click 1cm, 0mm}                     
    || キーボードで、altキーとtキーを同時にタイプする。
    {UI.type alt? = true, “t”}

    UIクラスはユーザインタフェースの操作をシミュレーションするために、列挙型UiGestureの値を使用します。以下の物があります。

    {define-enum public UiGesture
      || マウスジェスチャー
      press,
      release,
      move,
      click,
      right-click,
      double-click,

      || キーボードジェスチャー
      focus,
      type,
      press-key,

      || ターゲットオブジェクトのチェック
      check-selection,
      check-value,
      check-events,
      check-property,
      check,

      || その他のアクション
      clear-selection,
      do,
      scroll,
      set-value,
      set-view,
      wait
    }

    各ジェスチャーごとにコンストラクタがあります。たとえば、サンプルでも使用されていますが、pressジェスチャーについては以下のようになっています。

    {press
      || ターゲットオブジェクト内のx座標です。
      x:any,
      || ターゲットオブジェクト内のy座標です。
      y:any,
      || クリックするボタンです。
      button:int = left-button,
      ||GuiInputEventのフィールドに渡される値です。
      shift?:bool = false,
      ||GuiInputEventのフィールドに渡される値です。
      ctrl?:bool = false,
      ||GuiInputEventのフィールドに渡される値です。
      alt?:bool = false,
      ||GuiInputEventのフィールドに渡される値です。
      menu?:bool = false,
      ||GuiInputEventのフィールドに渡される値です。
      command?:bool = false,
      ||プラットフォームを指定できます(win32, linux, macなど)
      platform:String = “”,
      ||ターゲットとなるオブジェクトです。
      target:#Graphic = null,
      ||操作後、次のステップへ移る前の待機時間です。
      delay:Time = 50ms
    }

    ターゲットオブジェクトがTextControlだった場合、x,yを指定する際に単位を省略すると文字数を表します。

     

    計算レコードセット

    CalculatedRecordSetは、LocalRecordGridにセル間で計算する機能を付加します。セルの値が変更されると、値を参照しているセルの値も自動的に再計算されます。

    サンプル

    calcrec.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/calculatedemo.curl

    各行の値の合計値を右端の列に表示しています。

    使い方

    RecordSetを作成する代わりにCalculatedRecordSetのインスタンスを作成します。そのコンストラクタにはCalculatedFieldManagerクラスのインスタンスを渡します。以下の部分です。

    def rs1 = {CalculatedRecordSet manager, rf1,
        {RecordData index = 0, a = 3, b = 2, c = 25},
        {RecordData index = 1, a = 4, b = 3, c = 22},
        {RecordData index = 2, a = 5, b = 4, c = 21}
      }

    CalculatedRecordSetのコンストラクタは以下のようになっています。

    {default
      ||このレコードセットが操作するCalculatedFieldManagerです。
      manager:CalculatedFieldManager,     
      ||データアイテムの特徴を定義するフィールド記述子。ここではrf1を渡しています。
      fields:RecordFields,                  
      ||内容の変更が許可されているかどうかを示します。
      modifiable?:bool = true,
      …:Object
    }

    計算ロジックを定義します。CalculatedRecordSetから取り出したレコードをCalculatedRecordにキャストして、set-calculated-fieldメソッドに引数として渡します。

    {for record in rs1 do
      def rec = record asa CalculatedRecord
      {rs1.set-calculated-field
          rec,
          rf1[“row-sum”],
          update-proc = sum-proc,
      {rs1.get-or-create-calculated-field rec, rf1[“a”]},
      {rs1.get-or-create-calculated-field rec, rf1[“b”]},
      {rs1.get-or-create-calculated-field rec, rf1[“c”]}}
    }

    set-calculated-fieldメソッドの引数は以下のようになっています。

    {set-calculated-field 
      ||計算処理をセットするレコードです。
      record:CalculatedRecord,                       
      ||計算処理をセットするフィールドです。
      record-field:RecordField,              
      ||計算処理を定義するプロシージャ。CalculatedFieldUpdateProcTypeは
      ||{proc-type {CalculatedField}:void}と定義されていて、
      ||これが呼び出される際にここに渡される引数は、第二引数で指定したフィールドです。
     
      update-proc:#CalculatedFieldUpdateProcType = null,     
      ||レコードやフィールドが削除されるとき、自動的に削除されてもよいかどうかを設定します。
      weak-predecessors?:bool = false,        
      ||変更を検知するCalculatedFieldを指定します。
      …:CalculatedField                       
    }

    ここでは…引数をget-or-create-calculated-fieldの戻り値として渡しています。get-or-create-calculated-fieldは、引数で与えられるレコードとフィールドに関連付けたCalculatedRecordFieldを、必要であれば作成して返すメソッドです。
    get-or-create-calculated-fieldメソッドの引数は以下のようなものです。

    {get-or-create-calculated-field
      record:CalculatedRecord,      || 関係するレコード
      record-field:RecordField       || 関係するフィールド
    }

     

    ファイル操作API

    FileAppは一度に一つファイルを編集する標準的Curlアプリケーションのひな形となる抽象クラスです。標準的なファイルメニューを提供します。

    使い方

    Curlアプリケーションでこのクラスを継承します。

    コンストラクタは以下のようになっています。

    {default   
      || タイトルバーに表示されるアプレットの名前です。
      app-name:String,   
      || ファイル選択ダイアログに使用するフィルターです。
      filters:FileDialogFilterArray = FileDialogFilter.all-files-filter-array
    }

    以下のpublicメソッドがあります。

    file-new

    file-new“コマンドの実行時に実行されます。ただし、編集中のファイルに未保存の変更が確認できれば、閉じる前に保存するか、そのまま閉じるか、キャンセルするかを問い合わせ、その後抽象メソッドdo-file-newを呼びます。do-file-newはオーバライドする必要があります。

    file-open

    file-open“コマンドの実行時に実行されます。ただし、編集中のファイルに未保存の変更が確認できれば、閉じる前に保存するか、そのまま閉じるか、キャンセルするかを問い合わせます。その後、開きたいファイルのurlを抽象メソッドdo-file-openに渡します。do-file-openはオーバライドする必要があります。具体的な読み込み処理はそこに記述します。

    file-revert

    file-revert“コマンドの実行時に実行されます。未保存の編集内容は破棄されます。do-file-openを呼んでファイルを読み込み直します。

    file-save

    file-save“コマンドの実行時に実行されます。ファイル名が未設定なら保存場所を決めるダイアログを表示します。その後、do-file-saveまたはdo-file-save-asを呼びます。do-file-saveはオーバライドする必要があります。具体的な保存処理はそこに記述します。

    file-save-as

    file-save-as“コマンドの実行時に実行されます。ファイルの保存場所を決めるダイアログを表示して名前を決めた後、do-file-save-asを呼びます。具体的な保存処理はオーバライドされたdo-file-saveに記述されたものが実行されます。

    exit

    exit“コマンドの実行時に実行されます。アプレットを終了します。ただし、編集中のファイルに未保存の変更が確認できれば、閉じる前に保存するか、そのまま閉じるか、キャンセルするかを問い合わせます。

    get-file-menu

    これらのコマンドをMenuActionにひもづけたSubMenuを返します。

    note-edited

    アプリケーション上でファイルの内容に編集が施されたときに呼び出してください。このメソッドを呼ぶことにより、編集内容が保存を必要としていることをsave-needed?アクセサの値から知ることが可能になります。

    note-file-saved

    ファイル保存が行われたときには自動で呼び出されます。このメソッドを呼ぶことにより、編集内容の状態が保存を必要としないことをsave-needed?アクセサの値から知ることが可能になります。

    サンプル

    fileapp.jpg

    http://developers.curlap.com/curl/curl-ext/hp2/fileappdemo.curl

    ごくシンプルなテキストエディタです。TextArea内に編集を加えると、ファイルメニューから「新規」や「開く」を選択したときに、保存するかどうかを問い合わせるダイアログが出ます。「開く」や「保存」を行って以降未編集の状態なら、「新規」や「開く」を選択しても問い合わせは出ません。この判断をするためのコードをほとんど書かずにこの動作が実現できていることにご注目ください。

     

    バックグラウンド・タスクAPI

    別スレッドでタスクを実行する機能としてBackgroundTaskQueueクラスが提供されます。BackgroundTaskQueueクラスで定義されるasync-start-taskプロシージャは、サブアプレットの中でコードを実行し、その結果を取得します。UIとの対話処理をブロックしないように、異なるスレッドでコードを実行することができます。これによりマルチコアやハイパースレッディングを含む最近のCPUのパワーのアドバンテージを利用することができるでしょう。

    サンプル

    http://developers.curlap.com/curl/curl-ext/hp/BackgroundTas/sample/start.curl

    backgroundtaskdemo.jpg

     

     

    このサンプルアプレットは、上図のようなマンデルブロ集合と呼ばれるフラクタル図形を表示します。フラクタル図形は細部を拡大しても無限に自己相似な図形が現れ続けるという興味深い性質を持つ図形です。このアプレットの表示は左クリックで拡大、Shift+左クリックで縮小しますのでその様子を確認してみてください。

    この図形は細部を描写するために時間のかかる計算を必要とします。このアプレットでは画面を128ピクセルの正方形で分割して、それぞれの領域の演算を複数のスレッドで同時に行っていきます。計算の終わったスレッドが算出した領域から順次表示していきますので、必ずしも左上から一領域ずつ順番に描写されない点、また、描画途中でも拡大、縮小のクリック操作を受け付ける点に注目してください。

     

    使い方

    start.curlのredrawメソッド内の以下の部分でBackgroundTaskQueue.async-start-taskの機能が使用されています。

     {for x-index = 0 below self.x-pixels step self.step-value do         set y0 = self.min-y         {for y-index = 0 below self.y-pixels step self.step-value do             def x = x-index             def y = y-index            || 演算処理をキューに入れ る             {BackgroundTaskQueue.async-start-task                 "calculate-rectangle",                 {Arguments x0, y0, increment, self.step-value},                 package-selector =                     {make-package-selector                         "COM.CURL.EXT.BACKGROUND-TASK.MANDLEBROT-SAMPLE",                         location = {url "mand.scurl"}                     },                 queue = self.queue,                 {on e:BackgroundTaskEvent do                     ||ズームのためにマウスがクリックされてタスクがキャンセルされるとき e.canceled? は true。                     {if e.exception == null and not e.canceled? then                         || タスク終了                         {dec self.working-tasks}                         || {Array-of bool} がこの正方形の領域に関する計算結果                         def r = e.result[0] asa {Array-of bool}                         || 演算結果に従ってPixmapを描画                         {mutate-fill-pattern p:Pixmap on self.fill-pattern do                             let r-index:int                             {for i = 0 below self.step-value do                                 {for j = 0 below self.step-value do                                     {p.set x + i, y + j,                                         {if r[r-index] then                                             {Pixel.from-uint8 0, 0, 0}                                          else                                             {Pixel.from-uint8 0xff, 0xff, 0xff}                                         }                                     }                                     {inc r-index}                                 }                             }                         }                     }                 }             }             || タスクを一つキューに入れた             {inc self.working-tasks}             set y0 = y0 + (increment * self.step-value)         }         set x0 = x0 + (increment * self.step-value)     }

    BackgroundTaskQueueクラスのasync-start-taskプロシージャが二重ループの中で呼び出されています。そのたびごとにcalculate-rectangleプロシージャを呼び出すタスクがキューに追加され、可能ならば実行されます。calculate-rectangleプロシージャには128ピクセル四方の正方形領域の演算が行われます。

     

    BackgroundTaskQueue.async-start-taskプロシージャの引数の定義は以下のようになっています。

    ||実行するプロシージャ、あるいはコンストラクタを実行するクラスの名前。
    proc-name:String
    ||proc-nameに渡す引数。
    args:Arguments
    ||proc-nameを探すパッケージをインポートするために使われるパッケージセレクタ(デフォルト:null)
    package-selector:#ComponentSelector
    ||package-selectorがパッケージを探すために使うマニフェスト。
    ||指定されない場合はmanifest-urlとroot-manifest-urlからの値が使用される。
    ||どちらも未指定の場合はカレントプロセスのデフォルトマニフェストが使用される。
    manifest:#ComponentManifest = {get-process-manifest},
    ||必要があれば、メインマニフェストのURL(デフォルト:null)
    manifest-url:#Url
    ||必要があれば、ルートマニフェストのURL(デフォルト:null)
    root-manifest-url:#Url
    ||このタスクを開始するために使用されるBackgroundTaskQueue。
    queue:BackgroundTaskQueue = {BackgroundTaskQueue.get-default-background-task-queue},
    ||BackgroundTaskEventを受け取るイベントハンドラ。
    event-handler:EventHandler
    …:EventHandler

    このサンプルではBackgroundTaskQueue.async-start-taskプロシージャのqueue引数にself.queueが渡されており、その値は以下のように記述されています。

    field queue:BackgroundTaskQueue = {BackgroundTaskQueue max-threads = 8, max-idle-threads = 8}

    BackgroundTaskQueueクラスのコンストラクタ引数定義は以下のようになっています。

    {default
    ||同時にアクティブになる最大スレッド数(デフォルト:4)
    max-threads:int
    ||同時にアイドル状態になる最大スレッド数(デフォルト:0)
    max-idle-threads:int
    ||BackgroundTaskRemoteInterfaceの呼び出しに応えるサブアプレットのURL
    async-task-applet-url:Url = {BackgroundTaskQueue.default-async-task-applet-url}

     

    アニメーション画面遷移

    Curl External Libraryには、アニメーションによる画面遷移ができるコンポーネントが含まれています。画面遷移も通常の画面の切り替えとダイアログなどのポップアップウィンドウなどにも適用できます。

    transition-frame.png

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    使い方

    これを利用するには、COM.CURL.EXT.TRANSITION-LIBRARYパッケージのTransitionFrameクラスを利用します。

    まずはTransitionFrameのインスタンスを生成します。

    def tf =
      {TransitionFrame
          background = “white”,
          border-color = “blue”,
          border-width = 1px,
          transition-effect = {CrossFadeTransitionEffect}
      }

    次に、このTransitionFrameに遷移する元や先のコンテナ(Frameなど)を追加します。

    {tf.add {Frame width=5cm, height=5cm, background=”red”}}

    {tf.add {Frame width=5cm, height=5cm, background=”blue”}}

    {tf.add {Frame width=5cm, height=5cm, background=”yellow”}}

    画面の切り替えは、set-active-screenメソッドによって、アニメーションを伴った画面遷移が可能となります。

    || 引数には、tfにaddされたコンテナの番号(スタートは0)を指定します。(左の例では2個目にaddしたFrame)
    {tf.set-active-screen 1}

    また、いろいろなエフェクトをTransitionFrameのtransition-effectプロパティに指定することで、アニメーション方法を変更できます。例えば、CrossFadeTransitionEffect、DoorOpenTransitionEffect、Spin3dTransitionEffect、StiffPageTurnTransitionEffect、PageTurnTransitionEffect、ExplodeTransitionEffect/ImplodeTransitionEffectなどその他多数のエフェクトが用意されています。

    さらにこのエフェクトクラスに、durationやpacingを指定することで、アニメーションの速度を変更できますし、orientationを指定することでアニメーションの方向を変更できます。特にpacingを指定することで徐々に早くしたりすることもできます。

    {DoorOpenTransitionEffect duration = 0.5s, pacing = {cubic-bezier 0.5, 1}, orientation = “horizontal”}

    アニメーションを用いたウィンドウのポップアップについては、AnimatedViewクラスを利用します。アニメーションのエフェクトはGrowViewAnimatorやfadeViewAnimator、GenieViewAnimatorなどがあります。

    def v =
      {AnimatedView
            {Frame width=3cm, height=3cm, background=”red”}, 
            animator = {GrowViewAnimator duration=0.5s, pacing={cubic-bezier 0.5, 1}}
      } 
    {v.show}

     

    サンプル

     

    ヘルプドキュメントか、もしくはソースコードのdocs/samples/sample-transition-frame.curlやdocs/samples/sample-view-animation.curlが非常に参考になります。