大量データを高速に表示できる RecordGrid ですが、
それでもカラムの数が膨大になってくると、スクロールや描画がモタつくことがありますよね。
とくにRecordGridCell などを継承して、RecordGridColumn のscell-spec に適用したカスタムセルを利用すると
その違いが顕著になるような気がしています。
少しでもパフォーマンスを上げたいときは、どんなことに気をつければいいのでしょうか。
もしそのセル(カラム)がIME入力を必要としないならば、
input-method-enabled? = false とすると、
矢印キーでのセル間のフォーカス移動がすばやくなるようです。
これは、セルが入力状態になるたびにIMEのON/OFFが切り替わっているのをスキップするためです。
RecordGrid のパフォーマンスは、主に各セル(カラム)の refresh-data メソッドの処理に依存するようです。
そのため、カスタムセルを利用する際、継承先のクラスでは、
なるべくこのメソッド内の処理を簡潔にすることがパフォーマンス向上の近道のようです。
また、データが存在せず、再描画しなくてもよいカラムなどがあれば、
refresh-data のなかで{supre.refresh-data} を呼ばないようにスキップすることで、
全体の描画速度が向上すると思います。
セルのプロパティにある possibly-displayed? を参照して下記のような記述をすると、
体感ですが、若干スクロールのスピードが上がったような気がしないでもなくもないです。
Code:
{if self.possibly-displayed? == true then
{super.refresh-data}
else
{after 0s do
{if self.possibly-displayed? == true then
{super.refresh-data}
}
}
}
(08-24-2011, 04:23 PM)umemura Wrote: [ -> ]もしそのセル(カラム)がIME入力を必要としないならば、
input-method-enabled? = false とすると、
矢印キーでのセル間のフォーカス移動がすばやくなるようです。
これは、セルが入力状態になるたびにIMEのON/OFFが切り替わっているのをスキップするためです。
どうやらIMEツールバーによってフォーカス移動の速度が変わる様です。
大量カラム、大量データを持たせたRecordGridにて速度の検証をしてみましたが、
Microsoft IME2003ではinput-method-enabled? = falseをしなくてもフォーカス移動の遅延はほとんどありませんでしたが、
Microsoft IME2007ではinput-method-enabled? = falseをしないとかなりフォーカス移動の遅延が見受けられました。
これはIMEツールバーの種類によって、IMEのON/OFF速度が異なるからなのでしょうか
(08-24-2011, 04:23 PM)umemura Wrote: [ -> ]input-method-enabled? = false とすると、
矢印キーでのセル間のフォーカス移動がすばやくなるようです。
(09-02-2011, 07:18 PM)森口 慶紀 Wrote: [ -> ]どうやらIMEツールバーによってフォーカス移動の速度が変わる様です。
ちなみにセルの上下移動(↑or↓)のときに大きく影響がでるようですね。
(08-24-2011, 04:15 PM)umemura Wrote: [ -> ]少しでもパフォーマンスを上げたいときは、どんなことに気をつければいいのでしょうか。
私は以下を気をつけます。
・設計段階でカラム数(表示している列数)を多くならないようにする
・継承したRecordGridCellクラスのrefresh-dataメソッドやformat処理に以下のような処理を書かない
→Recordの値をセットする(RecordSetEventイベントが発生してしまうため)
→Recordを検索する(RecordSet.selectなど)
・表示のみのカラムであればStandardFixedStringCell(またはそれを継承したクラス)を使用する
また思い出したら追記します。
影響が大きい割によく忘れられがちなのは、プログラムからレコードの変更、追加、削除などを行うときに batch-events?=true を指定しないこと。これは痛い。
Code:
{with record-set.batch-events? = true do
|| レコードの変更、追加、削除など
}
厳密には、すでにRecordGridに関連づいているRecordSetに対して複数の変更(Recordに値をセットするとか、RecordGrid.appendするとか)を同時に行う場合に必須です。使いどきの判断が難しいと思う場合はなにも考えずに毎回これをかきましょう。イディオムです。
グリッドの表示領域が増えれば増えるほど、
画面に表示されるデータ(セル)が多くなる程、
描画に時間がかかる為、スクロールが遅くなってしまいますよね
RecordGrid.batch-events?=true を指定するのとしないのとでは、かなりパフォーマンスに影響がありますね。
また、別スレッドの「セル単位での色指定」でも記載しましたが、
RecordGridCell.refresh-data の中で、このbatch-events?を参照するようにすると、
さらに全体のパフォーマンスが向上しました。
Code:
{curl 8.0 applet}
{curl-file-attributes character-encoding = "utf8"}
{applet manifest = "manifest.mcurl",
{compiler-directives careful? = true}
}
{define-class public open CustomCell
{inherits StandardStringCell }
{constructor public {default}
{construct-super}
}
{method public open {refresh-data}:void
||RecordSet.batch-events?=true の間は、
||再描画処理を行わない
{if-non-null record = self.record,
rs = self.record.record-set
then
{if not rs.batch-events? then
{super.refresh-data}
let (data:String, valid?:bool) = {self.get-formatted-data}
{if {data.to-int} > 10 then
set self.background = "pink"
else
{unset self.background}
}
}
}
}
}
{define-class public open CustomCell2
{inherits StandardStringCell }
{constructor public {default}
{construct-super}
}
{method public open {refresh-data}:void
{super.refresh-data}
let (data:String, valid?:bool) = {self.get-formatted-data}
{if {data.to-int} > 10 then
set self.background = "pink"
else
{unset self.background}
}
}
}
{def rf-ary = {{Array-of RecordField}}}
{def col-ary = {{Array-of RecordGridColumn}}}
{def col-ary2 = {{Array-of RecordGridColumn}}}
{for i:int = 1 to 100 do
def rf-name = "field-" & i
{rf-ary.append {RecordField rf-name}}
{col-ary.append {RecordGridColumn rf-name, cell-spec = CustomCell}}
{col-ary2.append {RecordGridColumn rf-name, cell-spec = CustomCell2}}
}
{def rs = {RecordSet {RecordFields {splice rf-ary}}}}
{def rs2 = {RecordSet {RecordFields {splice rf-ary}}}}
{def grid =
{RecordGrid
height = 5in, width = 3in,
record-source = rs
, {splice col-ary}
}
}
{def grid2 =
{RecordGrid
height = 5in, width = 3in,
record-source = rs2
, {splice col-ary2}
}
}
||レコードの作成
{define-proc public {init-record rs:RecordSet}:void
{rs.delete-all}
{rs.commit}
{for i:int = 0 to 5000 do
def new-r = {rs.new-record}
{for rf in rs.fields do
set new-r[rf.name] = {String i}
}
{rs.append new-r}
}
}
{CommandButton
label = "クリア",
{on Action do
{rs.delete-all}
{rs.commit}
{rs2.delete-all}
{rs2.commit}
}
}
{HBox
{VBox
"refresh-data を ",
"batch-event?=true 時にキャンセルする",
{HBox
{CommandButton
label = "batch-events?あり",
{on Action do
||def dt = {DateTime}
{with rs.batch-events? = true do
{init-record rs}
}
||{popup-message {dt.elapsed}}
}
},
{CommandButton
label = "batch-events?なし",
{on Action do
||def dt = {DateTime}
{init-record rs}
||{popup-message {dt.elapsed}}
}
}
},
grid
},
{VBox
"refresh-data を ",
"常に処理する",
{HBox
{CommandButton
label = "batch-events?あり",
{on Action do
||def dt = {DateTime}
{with rs.batch-events? = true do
{init-record rs2}
}
||{popup-message {dt.elapsed}}
}
},
{CommandButton
label = "batch-events?なし",
{on Action do
||def dt = {DateTime}
{init-record rs2}
||{popup-message {dt.elapsed}}
}
}
}
, grid2
}
}