CodeZine(コードジン)

特集ページ一覧

全機能を使い倒せ!大量データもグラフィカルに表示するCurlコントロール「RecordGrid」マニア

  • LINEで送る
  • このエントリーをはてなブックマークに追加

 CurlのGUIコントロールの1つである「RecordGrid」。この記事では、業務アプリケーションには欠かせないこのコントロールを使って、よりグラフィカルで、洗練された機能を実現するコツを紹介します。

はじめに

 RecordGridはCurlのGUIコントロールの1つであり、その操作性の高さ、機能の充実さから数多くの業務アプリケーションで使用されています。

 本稿では、既に数多く使用されているRecordGridの基本機能ではなく、知られざるRecordGridの設計思想よりパフォーマンスの高い利用方法など、さらなるディープな部分について解説します。また、RecordGridの機能を強化する今後の展開についても話していきたいと思います。

RecordGridを使って実装した表計算アプリ
RecordGridを使って実装した表計算アプリ
※注意

 基本機能については、CurlヘルプドキュメントのCurl開発者ガイドより、[データの管理と表示]-[データレコードとグリッド]を参照ください。

RecordGridの深イイ話

大量データでも素早く表示 ! RecordGridCellの概念

 RecordGridは、データの集まりであるRecordSetオブジェクトを使用しています。RecordSetオブジェクトはRecordを複数持つような形で、業務によっては数千から数万という大量のデータを保持することがあります。

 これらのデータを実際に表示しているのはRecordGridCellオブジェクトです。全ての行列のセルオブジェクトを生成しているのではなく、RecordGrid上に表示されている箇所のみのRecordGridCellオブジェクトが生成されています。

 次の図は、10,000件のデータをRecordGridで表示したものです。

10,000件のデータをRecordGridで表示
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}
}

 これを実行すると、次の図のようになります。

3の倍数のデータを強調して表示している
3の倍数のデータを強調して表示している

 このように、特定の値を持った行やセルに対して色の変更、文字サイズの変更などによって強調表示を行うことで、例えばエラー行などに注目を集めるようなビジュアルにできます。

 もちろん、表示を変更するだけでなく、このセルの中にコマンドボタンやテキストフィールドなどのコントロール部品を埋め込むことも可能となります。コントロール部品を埋め込むことで、コマンドボタンであればユーザーに対して、この行に関する何らかのアクションが発生するというイメージを明確に与え、また、テキストフィールドであれば、行データに関して入力できるというイメージを明確にできます。

 次のイメージは、リンクに見えるコマンドボタンを埋め込むことで、タイトルをクリックすると詳細が表示されるという印象をユーザーに与えています。

コマンドボタンのコントロールを埋め込んでいる
コマンドボタンのコントロールを埋め込んでいる

 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

 では、このTreeGridはどのように実装されているのか、実際にソースコードを見てみましょう。TreeGridが主に実装されているファイルは、COM.CURL.EXT.DATA-ACCESSパッケージのtreegrid.scurlです。

CURL-EXT-V0.6.1/COM.CURL.EXT-V0.6.1-src/code/GUI/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、RecordSetのカスタマイズで複雑な表現や機能を実現したGantt Chart
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の新しい機能を見せるために設定されています。

DataGridを使用した例
DataGridを使用した例
  • オレンジ色の線の中にある行は、線の色と広さは他の行と違っており、とても目立ちます。それとオーバーレイも追加されていて、隣の行と比べて薄い色になっています(RecordGridでは、各線は同じ色と広さです)。
  • 行の高さはそれぞれ設定できます(RecordGridでは、ある程度は可能ですが、制限もあります)。
  • 行にも、列にも、ヘッダーとフッターがあります。フッター列は3列あって、この場合に各列は違うテキストの色が設定されています(RecordGridには、列のヘッダーと行のヘッダーだけがあります)。
  • ヘッダーとフッターは専用の線でコンテンツと分けられています。上の例では、3つの赤線と白くて太い線があります。

 RecordGridだけでなくDataGridのさまざまな機能によって、業務アプリケーションのビジュアルに大きな変化をもたらすことができます。

まとめ

 RecordGridは、業務アプリケーションにおいて欠かせない存在です。RecordGridの深く知られていない機能や設計思想を用いて、業務アプリケーションにおいて、よりグラフィカルで、洗練された機能の実現につながれば幸いです。

 また、現在開発中のDataGridにも、ユーザーの皆さまから寄せられた要望をぎっしり詰め込む予定です。ぜひ、ご期待ください。

  • LINEで送る
  • このエントリーをはてなブックマークに追加

著者プロフィール

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5