タイトルイメージ 本文へジャンプ
Curlテクノロジー >> WEBトレーニング


ステップ6:グラフィカル ユーザーインターフェース(後編)

curl™

Curlにはデータを表形式で表示する RecordGrid と呼ばれるグリッドコントロールが付属しています。列を表現するRecordクラスのコレクションとしてRecordRecordSetクラスが用意されており、この情報を作成してグリッドに表示させます。
本ステップでは簡単なグリッドを作成し、システム構築でポイントになりそうな概観の操作について説明します。

■RecordGridの概要

RecordGridはその名の通り行レコードデータを管理するために幾つかのナビゲーション機能が実装されています。RecordGridのコンストラクタに何も指定しない状態では列ヘッダー、選択行を示すレコードセレクター、行移動に便利なナビゲーションバーなどが表示されています。



 step6_1.dcurl
{curl 4.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

{let items:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "番号", domain = String},
            {RecordField "商品名", domain = String},
            {RecordField "quantity", domain = int}
        },
        {RecordData 番号 = "1", 商品名 = "バナナ", quantity = 100},
        {RecordData 番号 = "2", 商品名 = "りんご", quantity = 2000},
        {RecordData 番号 = "3", 商品名,"マンゴー", quantity = 150}
    }
}
{let grid:RecordGrid = 
    {RecordGrid
        record-source = items
    }
}

{View
    grid,
    visibility = "normal"
}
まずitemsという名前でRecordSetクラスのインスタンスを作成します。RecordSetは表構造(実際は列)と表示データを管理する目的で使用され、この例ではRecordFieldクラスにて表構造を定義し、RecordDataクラスにて表示データを追加しています。RecordFieldsはRecordFieldのコレクションを扱うために使用されます。

RecordDataはRecordSet.appendメソッドなど後から追加や削除する事も可能でキー=バリュー形式もしくはキー、バリュー形式にてRecordFieldsに対応するハッシュ情報を加えていきます。

次に先ほど作成したitemsを表示データとしてコンストラクタに渡し、gridという名前でRecordGridクラスのインスタンスを作成しています。

■RecordGridの概観を制御

ローカル オプションを指定すると概観形状を変更させる事ができるので用途に合わせたデザインが可能になります。 上記から変更された画面とソースは以下の通りです。



 step6_2.dcurl
{curl 4.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

{let items:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "番号", domain = String},
            {RecordField "商品名", domain = String},
            {RecordField "quantity", domain = int}
        },
        {RecordData 番号 = "1", 商品名 = "バナナ", quantity = 100},
        {RecordData 番号 = "2", 商品名 = "りんご", quantity = 2000},
        {RecordData 番号 = "2", 商品名 = "マンゴー", "quantity", 150}
    }
}
{let rg:RecordGrid = 
    {RecordGrid
        record-source = items,
        height = 3cm,
        alternate-row-background = "#80ff80",
        grid-line-color = "#006a00",
        display-column-headers? = false,
        display-record-selectors? = false,
        column-selection-enabled? = true,
        multiple-selection-enabled? = false,
        display-filler-column? = true,
        record-selection-enabled? = false,
        display-navigation-panel? = false
    }
}

{View
    rg,
    visibility = "normal"
}
display-column-headers?などのプロパティを無効にしてナビゲーション機能を非表示にしました。一番右側にあるquantityの横にも列が表示されていますが、これはスクロールバーが表示される領域が予約されている為です。alternate-row-backgroundプロパティは2行毎の背景色を指定できます。簡単な表であればこれだけで足りるかもしれません。

■RecordGridのセル内容を制御

RecordFieldクラスに定義するdomain引数にCurlのプリミティブ型を指定すると値と内容の整合性などを検査するDomainが生成されます。int型に指定した小数部が適切にキャストされている、bool型のセル表示形状が変わっている点などに注目してください。



 step6_3.dcurl
{curl 4.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

{let items:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "String", domain = String},
            {RecordField "Int", domain = int},
            {RecordField "Double", domain = double},
            {RecordField "Bool", domain = bool},
            {RecordField "Char", domain = char}
        },
        {RecordData 
            String = "ABC", Int = 123.4, Double = 234.5, Bool = true,Char="\u0062"
        }
    }
}
{let grid:RecordGrid = 
    {RecordGrid
        record-source = items,
         width = 15cm
    }
}

{View
    grid,
    visibility = "normal"
}
intに指定した .4が切り捨てられ、boolではチェックボックスがセルのユーザインターフェースとして表示されている事が分かります。

■RecordGridのセルに色を付ける

上記の例ではプロパティやコンストラクタを指定して全体的な概観をコントロールする事が出来ました。またRecordGrid.columnsアクセサなどから特定列の変更も可能ですが個別セルに対する修飾をプロパティから行う事は出来ません。

RecordGridではセル作画を拡張する幾つかのサブクラスが用意されています。以下はStandardRecordGridCellと呼ばれるクラスを継承して作成され在庫数が0個の場合は背景をピンク色に変更しています。

在庫数が0になるとセル背景色が変更されるルールが基本ロジックと分離出来ている点に注目してください。このルール(クラス)は他の画面でも使用できる上いつでも変更可能です。



 step6_4.dcurl
{curl 4.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

||--
||-- 在庫数量に応じたセル背景色を設定するクラス
||--
{define-class public open StockColorCell
  {inherits StandardRecordGridCell}

  field private _color_frame:Frame = 
      {Frame width={make-elastic}, height={make-elastic}}

  {constructor public {default}
    {construct-super}
    {self.add-internal self._color_frame}
    set self.cells-take-focus? = self.can-update?
  }

  {method public open {refresh-data}:void
    let (data:String, valid?:bool) = {self.get-formatted-data}
    {if valid? and data != "" then
        {if data == "0" then
            set self._color_frame.background = {Background "pink"}
         else
            set self._color_frame.background = "transparent"
        }
        {self._color_frame.add replace?=true, data}
     else
        {unset self._color_frame.background}
    }
  }
}

{let item-set:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "no",     caption = "商品番号", domain = int },
            {RecordField "name",   caption = "商品名称", domain = String},
            {RecordField "stocks", caption = "在庫数",   domain = int}
        },
        {RecordData no=1, name="バナナ",  stocks=10}, 
        {RecordData no=2, name="ドリアン",stocks=0 }, 
        {RecordData no=3, name="メロン",  stocks=5 } 
    }
}

{let custom_grid:RecordGrid = 
    {RecordGrid
        record-source = item-set,
        width = 12cm,
        {RecordGridColumn width = 2cm, "no", halign = "right"}, 
        {RecordGridColumn width = 5cm, "name" },
        {RecordGridColumn width = 3cm, "stocks", cell-spec = StockColorCell}
    }
}

{View
    custom_grid,
    visibility = "normal"
}
 cell-spec

拡張するクラスを適用するためセルを管理するRecordGridColumnクラスに対してcell-specを指定しています。
{RecordGridColumn width = 3cm, "stocks", cell-spec = StockColorCell}
 StockColorCell

StockColorCellはIDEに組み込まれたStandardRecordGridCellを継承して実装しています。クラス内で宣言したFrameクラスをコンストラクタ内のadd-internalメソッドにて指定する事でセル作画フレームを置換しています。{refresh-data}メソッドでは作画要求が発生した際の処理を記述しておりセルにセットされたデータを{self.get-formatted-data}にて取得しています。その結果が0の場合はbackgroundを変更しています。
{define-class public open StockColorCell
  {inherits StandardRecordGridCell}

  field private _color_frame:Frame = 
      {Frame width={make-elastic}, height={make-elastic}}

  {constructor public {default}
    {construct-super}
    {self.add-internal self._color_frame}
    set self.cells-take-focus? = self.can-update?
  }

  {method public open {refresh-data}:void
    let (data:String, valid?:bool) = {self.get-formatted-data}
    {if valid? and data != "" then
        {if data == "0" then
            set self._color_frame.background = {Background "pink"}
         else
            set self._color_frame.background = "transparent"
        }
        {self._color_frame.add replace?=true, data}
     else
        {unset self._color_frame.background}
    }
  }
}
RecordGridの入力した内容によりセルに色を付けるには?

上記の例ではFrameクラスを作画コンテナとして使用していたのでセルに対して入力が出来ませんでした。ではグリッド内のセルを入力するにはどうしたらよいでしょうか。RecordGridにはユーザーの入力インターフェースを持たせるためにStandardBaseEditableStringCell抽象クラスが用意されています。このクラスを使用する例としてサブクラスが用意されておりStandardStringCellおよびStandardDropdownCellはこの具象クラスにあたります。

この例ではStandardStringCellクラスを継承して作成しており、入力した在庫数が0個の場合は背景をピンク色に変更しています。セル内の値を変更して変化を確認してください。

グリッドを使用する画面は一般的に扱うデータ量が多いためセルに対して入力可能にするのかデザイン時によく検討してください。表示に対するパフォーマンスはより複雑なロジックを実装すると遅くなります。



 step6_5.dcurl
{curl 4.0 applet}
{curl-file-attributes character-encoding = "shift-jis"}
{applet manifest = "manifest.mcurl",
    {compiler-directives careful? = true}
}

||--
||-- 在庫数量に応じたセル背景色を設定するクラス
||--
{define-class public open StockEditableColorCell
  {inherits StandardStringCell}

  {method public open {refresh-data}:void
    let (data:String, valid?:bool) = {self.get-formatted-data}
    {if valid? and data != "" then
        {if data == "0" then
            set self.background = {Background "pink"}
         else
            set self.background = "transparent"
        }
     else
        {unset self.background}
    }
    {super.refresh-data}
  }
}

{let item-set:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField "no",     caption = "商品番号", domain = int },
            {RecordField "name",   caption = "商品名称", domain = String},
            {RecordField "stocks", caption = "在庫数",   domain = int}
        },
        {RecordData no=1, name="バナナ",  stocks=10}, 
        {RecordData no=2, name="ドリアン",stocks=0 }, 
        {RecordData no=3, name="メロン",  stocks=5 } 
    }
}

{let custom_grid:RecordGrid = 
    {RecordGrid
        record-source = item-set,
        width = 12cm,
        {RecordGridColumn width = 2cm, "no", halign = "right"}, 
        {RecordGridColumn width = 5cm, "name" },
        {RecordGridColumn width = 3cm, "stocks, cell-spec=StockEditableColorCell}
    }
}

{View
    custom_grid,
    visibility = "normal"
}

※ポイント:拡張コントロールが置かれているソースの場所は?

コアロジックは残念ながらソースが公開されていません。ただしコントロール内部の動作をより把握するためにいくつかの拡張コードが用意されています。標準でインストールすると以下のディレクトリに格納されていますので、詳しく知るためにもドキュメントと共に確認してみてください。

C:\Program Files\Curl Corporation\Surge\5\ide\gui\controls

次のステップではイベント処理について確認してきます。






    Copyright © 2006 Creer, Inc. All rights reserved. 株式会社クレール