はじめに
RecordGridはCurlのGUIコントロールの1つであり、その操作性の高さ、機能の充実さから数多くの業務アプリケーションで使用されています。
本稿では、既に数多く使用されているRecordGridの基本機能ではなく、知られざるRecordGridの設計思想、よりパフォーマンスの高い利用方法など、さらなるディープな部分について解説します。また、RecordGridの機能を強化する今後の展開についても話していきたいと思います。
基本機能については、CurlヘルプドキュメントのCurl開発者ガイドより、[データの管理と表示]-[データレコードとグリッド]を参照ください。
RecordGridの深イイ話
大量データでも素早く表示 ! RecordGridCellの概念
RecordGridは、データの集まりであるRecordSetオブジェクトを使用しています。RecordSetオブジェクトはRecordを複数持つような形で、業務によっては数千から数万という大量のデータを保持することがあります。
これらのデータを実際に表示しているのはRecordGridCellオブジェクトです。全ての行列のセルオブジェクトを生成しているのではなく、RecordGrid上に表示されている箇所のみのRecordGridCellオブジェクトが生成されています。
次の図は、10,000件のデータをRecordGridで表示したものです。
表示のために使用しているRecordGridCellは、IDが0~12の行×3列分だけです。つまり、どれだけ大量のデータを扱っても、ユーザーが一度に見る行列はせいぜい数十行×数十列となり、それ以外はスクロールして見るということになります。このように、表示されている箇所のみRecordGridCellオブジェクトを作成することはメモリの節約、処理速度の向上につながります。
ただし、横スクロールが存在するような列データが大量にある場合は注意が必要です。RecordGridは見えるところだけRecordGridCellを保持するというのが基本なのですが、見えていない列であっても表示されている行に関してはRecordGridCellオブジェクトを保持しています。
上図のように、100行であっても横に日付列を持つような横に長いデータの場合、見えていない列であったとしてもRecordGridCellオブジェクトを持つため、意図せずメモリを大量消費し、処理速度に影響を及ぼすということになりかねません。大量の「行」データではなく、大量の「列」データをもつ画面を作成する場合は慎重になる必要があります。
セルのカスタマイズでここまでできる !
RecordGridCellは、RecordSetのデータを表示するために使用するということは前ページで述べましたが、セルをカスタマイズすることでより効果的なデータの見せ方が可能になります。
例えば、以下のようにカスタマイズされたRecordGridCellを使用すると、IDが3の倍数のデータに対してより一層強調して表示できます。
{define-class public MyStandardStringCell {inherits StandardStringCell} {constructor public {default ...} {construct-super ...} } ||refresh-dataメソッドはRecordGridCellが表示すべきデータを ||切り替えるメソッド ||スクロール等表示すべきデータが変わった場合に呼ばれる {method public {refresh-data}:void {super.refresh-data} let (data:String, valid?:bool) = {self.get-formatted-data} {if valid? and data != "" and self.record["ID"] mod 3 == 0 and ||ここでIDが3の倍数のデータを抽出 not self.selected? ||行が選択されている場合は何もしない then set self.background = "navy" set self.color = "white" set self.font-size = 14pt else {if not self.selected? then {unset self.background} {unset self.color} {unset self.font-size} } } } }
また、このセルをRecordGridに適用するには、以下のように記載します。
{RecordGrid record-source = people, height = 7cm, ||cell-specで適用するRecordGridCellを指定する {RecordGridColumn width = 1.3cm, "ID", cell-spec = MyStandardStringCell}, {RecordGridColumn width = 3cm, "First", cell-spec = MyStandardStringCell}, {RecordGridColumn width = 3cm, "Last", cell-spec = MyStandardStringCell} }
これを実行すると、次の図のようになります。
このように、特定の値を持った行やセルに対して色の変更、文字サイズの変更などによって強調表示を行うことで、例えばエラー行などに注目を集めるようなビジュアルにできます。
もちろん、表示を変更するだけでなく、このセルの中にコマンドボタンやテキストフィールドなどのコントロール部品を埋め込むことも可能となります。コントロール部品を埋め込むことで、コマンドボタンであればユーザーに対して、この行に関する何らかのアクションが発生するというイメージを明確に与え、また、テキストフィールドであれば、行データに関して入力できるというイメージを明確にできます。
次のイメージは、リンクに見えるコマンドボタンを埋め込むことで、タイトルをクリックすると詳細が表示されるという印象をユーザーに与えています。
Curl Apps Galleryより、上記サンプルのダウンロードが可能となっているので、ぜひ試してみてください。
RecordGridもここまでできる ! Curl External Library TreeGrid, Gantt Chart
これまで、RecordGridCellをカスタマイズする方法を紹介してきました。ここからは、RecordGridやそのデータであるRecordSetをカスタマイズし、RecordGridをこれまでとは違った表現をするコントロールに変えてみましょう。
5月に公開されたCurlの業務向けUIコンポーネント群「Curl External Library(Curl EXT)」にRecordGridをベースにカスタマイズされた2つのコンポーネント「TreeGrid」「Gantt Chart」があります。Curl EXTのコードはオープンソースで全て公開されており、ここからダウンロードが可能です。
Curl EXTのTreeGridは、RecordGridとTreeControlを足したような機能を持っています。1つの行に紐づく複数の行を折りたたんだり、広げたりできます。例えば、次図のように、購入した商品の合計金額行が複数の商品の購入金額を持っており、合計金額行のみを表示したり、購入した商品の一覧を広げて表示することなども可能です。
では、このTreeGridはどのように実装されているのか、実際にソースコードを見てみましょう。TreeGridが主に実装されているファイルは、COM.CURL.EXT.DATA-ACCESSパッケージのtreegrid.scurlです。
{doc-next {purpose Display data in a {docref RecordSet} as a tree with many columns. } } {define-class public open TreeGrid {inherits RecordGrid} {doc-next {purpose The {docref RecordSetTreeModel} associated with this {docref TreeGrid}. } } field protected _model:RecordSetTreeModel ・ ・ ・
確かに、TreeGridはRecordGridから継承されて作られていることがわかります。しかし、このTreeGridクラス自体の長さはそこまで大きくありません。ドキュメント用のコードを入れても160行程度です。追加された処理にも、大きな変更はないように見えます。しかし、TreeGridのコンストラクタを見てみると、以下のようになっています。
{constructor public {default model:RecordSetTreeModel, filter:#RecordFilter = null, header-options:RecordGridRowOptions = {RecordGridRowOptions}, ui-object:#RecordGridUI = null, draggable-items?:bool = true, icon-proc:#{proc-type {cell:RecordGridCell, state:DisclosureState }:Pixmap } = null, item-proc:#{proc-type {cell:RecordGridCell}:Graphic } = null, ... } set self._model = model set self.draggable-items? = draggable-items? set self.icon-proc = icon-proc set self.item-proc = item-proc {construct-super record-source = model.display-records, filter = filter, header-options = header-options, ui-object = ui-object, display-navigation-panel? = false, display-filler-column? = true, {splice ...}, sort = RecordSetTreeModel.pos-field, key-spec = RecordSetTreeModel.pos-field } }
TreeGridのコンストラクタには、見慣れないRecordSetTreeModelクラスがあります。TreeGridのスーパークラスであるRecordGridのコンストラクタへ渡すconstruct-superを見ても、record-source引数にそのクラスの持つdisplay-recordsオブジェクトが渡されています。つまり、RecordSetTreeModelクラスでツリー構造となるようなRecordSetオブジェクトを作り出している、このTreeGridのツリー感を出しているのは、ReordSetTreeModelであるというのが分かります。このように、RecordGridだけでなくRecordSetを工夫するだけでもこのような表現の仕方が可能になります。
次に、Gantt Chartは上記のTreeGridとRecordGridCellをカスタマイズしたGanttCellを組み合わせて作成されています。このGantt Chartは日時の列をドラッグによって左右にスライドできます。もちろん、全体がスライドするのではなく、指定した日時列だけを動かすことが可能です。これにより、各項目の期間が確認しやすくなっています。
グラフィック階層を見ることができるデバッガを使用してGantt Chartを見てみると、GanttCellをはじめ多くのカスタマイズされたセルや、ヘッダーにはドラッグで左右にスライドするためのクラスが使用されています。
このようにセルのカスタマイズ、RecordGrid、RecordSetのカスタマイズなどによって、このGantt Chartのように複雑な表現や機能を実現することが可能となります。
もう好きにして ! あなたの思うまま。RecordGridオープンコントール
これまで、RecordGridを継承して機能を追加する方法や、RecordGridCellをカスタマイズしてデータの表現を変える方法を紹介してきました。しかし、それでは限界があります。機能を追加、拡張したいと思っても、RecordGridを継承して追加することが不可能な場合があります。その場合はオープンコントロールを利用しましょう。
Curlにはコントロール部品のソースコードが公開されています。もちろん、RecordGridのソースコードも公開されており、ソースコードを改変することで追加したい機能、表現方法を変えることが可能です。オープンコントロールは、以下のディレクトリに含まれています。
C:\Program Files\Curl Corporation\Surge\8\ide\gui\controls
バージョン7のデフォルトインストールの場合、RecordGridに関するファイルは、以下のファイルになります。
feels/record-grid-feels.scurl logical-controls/record-grid-ui.scurl logical-controls/record-grid.scurl ui-generic/standard-record-grid-cells.scurl ui-skinnable/skinnable-record-grid-ui.scurl ui-skinnable/skinnable-record-grid-cell-uis.scurl ui-standard/standard-record-grid-cell-uis.scurl ui-standard/standard-record-grid-ui.scurl styled-controls/skinned-record-grid-uis.scurl
これらのファイルを修正することで、今まではより違ったRecordGridを作ることができます。例えば、セル全体に画像を設定したり、任意の部品の色を細かく設定することが可能となります。
RecordGridのソースコードを改変することで、拡張性が飛躍的に高まることが分かります。
RecordGridのさらなる進化!DataGrid
先日、Curl EXTをリリースしたばかりですが、さらに強力なDataGridがリリースされる予定です。現在、まだ開発中の段階ですが(リリースは2012年夏を予定)、ここでちょっとだけ紹介します。
データベースの構造を表示させるには、RecordGridはとても便利なツールです。しかし、実際には構造データの表示以外にもいくつものユースケースがあり、RecordGridの想定範囲を超えるものもあります。その問題を解決するのがDataGridです。
DataGrid概念
基本的に、DataGridはRecordGridと似ています。行、列、セルがあって、データソースに繋がり、見える範囲が縦横にスクロールでき、セルは自動的に作られて…など。しかし、DataGridはRecordGridに比べ、もっと自由に制御できます。行はレコードからだけでなく、任意に追加できます。例えば、計算を行う小計行と、セクションを分けるデータのない行の両方が可能です。行のグループ化や、親子関係も設定でき、ネイティブでツリーモデルとdisclosure view(開閉グループ)のサポートがあります。また、これまで非常に希望の多かったセル結合も可能になります。
ビジュアル的にも、DataGridはもっと自由に制御できます。列オブジェクトだけでなく、行オブジェクトにもアクセスできるため、各行の個別オプションもより簡単に設定できます。DataGridは列ヘッダーだけでなく、フッターも、そして行にも複数設定できます。
RecordGridと同様に、DataGridはセルオブジェクトをできるだけリサイクルしますが、広いテーブル(100列以上あるようなテーブル)の場合に、RecordGridより効率的です。DataGridはとてもオープンであり、さらにカスタマイズする場合にも、簡単に実装することが可能となっています。
次の例は、エンタープライズアプリケーションとしてはちょっと派手かもしれませんが、DataGridの新しい機能を見せるために設定されています。
- オレンジ色の線の中にある行は、線の色と広さは他の行と違っており、とても目立ちます。それとオーバーレイも追加されていて、隣の行と比べて薄い色になっています(RecordGridでは、各線は同じ色と広さです)。
- 行の高さはそれぞれ設定できます(RecordGridでは、ある程度は可能ですが、制限もあります)。
- 行にも、列にも、ヘッダーとフッターがあります。フッター列は3列あって、この場合に各列は違うテキストの色が設定されています(RecordGridには、列のヘッダーと行のヘッダーだけがあります)。
- ヘッダーとフッターは専用の線でコンテンツと分けられています。上の例では、3つの赤線と白くて太い線があります。
RecordGridだけでなくDataGridのさまざまな機能によって、業務アプリケーションのビジュアルに大きな変化をもたらすことができます。
まとめ
RecordGridは、業務アプリケーションにおいて欠かせない存在です。RecordGridの深く知られていない機能や設計思想を用いて、業務アプリケーションにおいて、よりグラフィカルで、洗練された機能の実現につながれば幸いです。
また、現在開発中のDataGridにも、ユーザーの皆さまから寄せられた要望をぎっしり詰め込む予定です。ぜひ、ご期待ください。