【入門編】ListBoxとCheckedListBoxの描画高速化:DrawModeをOwnerDrawFixedにして大量項目のカスタム描画でカクつきを防ぐ – Visual Basic (VB / VB.NET)解析バイブル

スポンサーリンク

こんにちは。現場で鍛え抜かれたシステムアーキテクチャの知見を、あなたに共有できることを嬉しく思います。

「ListBoxに数千件のデータを放り込んだら、スクロールするたびに画面がカクついて使い物にならない……」

これは、VB.NETのWindows Forms開発で誰もが一度は通る「洗礼」です。なぜ遅いのか? それは、標準のListBoxが「高機能すぎる」からです。Windowsが裏側で「ここはどんなフォントだ? 文字の色は? 背景は?」と、毎回律儀に計算して描画しているからです。

今日は、この「標準描画」の呪縛を解き放ち、`DrawMode.OwnerDrawFixed` を使って、あなたのアプリケーションを爆速に変える極意を伝授します。

—

1. なぜ「OwnerDraw」が速いのか?

標準のListBoxは、一つ一つの項目を描画するたびに、OSの複雑な描画エンジンを呼び出します。アイテムが1,000個あれば、スクロールのたびにその計算が繰り返される。これが「カクつき」の正体です。

`OwnerDrawFixed`(固定サイズ・オーナードロー)に設定すると、Windowsからの「描画してくれ」という命令に対し、「はい、私が描きます。計算は全部パスしていいですよ」と横取りできる状態になります。描画の全責任を開発者が負う代わりに、無駄な処理をすべて削ぎ落とせるため、圧倒的なパフォーマンスを手に入れられるのです。

—

2. 実践:爆速ListBoxを実装する

まずは、ListBoxのプロパティを以下のように設定してください。

  • DrawMode: `OwnerDrawFixed`
  • ItemHeight: `20` (お好みの高さでOK)

次に、実際に描画を担当するイベントハンドラ(`DrawItem`)を記述します。

”’

”’ ListBoxの各項目を描画するイベント
”’ ここを軽量化するのがパフォーマンス向上の鍵です
”’

Private Sub ListBox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles ListBox1.DrawItem
‘ アイテムがない場合は何もしない
If e.Index < 0 Then Return ' 描画対象のListBoxを取得 Dim lb As ListBox = DirectCast(sender, ListBox) ' 背景色の決定(選択状態なら青系、そうでなければ白系) Dim backColor As Color = If((e.State And DrawItemState.Selected) = DrawItemState.Selected, SystemColors.Highlight, lb.BackColor) Dim foreColor As Color = If((e.State And DrawItemState.Selected) = DrawItemState.Selected, SystemColors.HighlightText, lb.ForeColor) ' 1. 背景を塗りつぶす(ここを削るとカクつく原因になります) Using b As New SolidBrush(backColor) e.Graphics.FillRectangle(b, e.Bounds) End Using ' 2. 文字を描画する Dim text As String = lb.Items(e.Index).ToString() Using b As New SolidBrush(foreColor) ' 文字の配置を調整(上下中央寄せ) Dim format As New StringFormat() With {.LineAlignment = StringAlignment.Center} e.Graphics.DrawString(text, e.Font, b, e.Bounds, format) End Using ' 3. フォーカス枠を描画(必要に応じて) e.DrawFocusRectangle() End Sub ---

3. ここで陥りやすい「罠」

コードを見て「おや?」と思った方は鋭いです。以下の2点に注意してください。

① `Using` ステートメントの重要性

`SolidBrush` などの描画リソースは、OSのメモリを直接消費します。`Using` を使わずに放置すると、メモリリークを起こし、数時間動かしただけでアプリが重くなります。「使い終わったら即破棄」は、VB.NETのメモリ管理の鉄則です。

② 大量更新時は `BeginUpdate` / `EndUpdate`

描画の高速化以前の話ですが、数千件のデータを追加する際は、必ず `ListBox1.BeginUpdate()` で描画を一時停止させ、追加完了後に `EndUpdate()` を呼んでください。これだけで、描画回数が劇的に減ります。

—

4. さらなる高みへ:CheckedListBoxの場合

`CheckedListBox` も同様に `DrawMode.OwnerDrawFixed` が使えます。チェックボックスの部分も自分で描画する必要がありますが、`ControlPaint.DrawCheckBox` という便利なメソッドが用意されています。

‘ DrawItem内にてチェックボックスを描画する例
ControlPaint.DrawCheckBox(e.Graphics, e.Bounds.X + 2, e.Bounds.Y + 2, 16, 16,
If(CheckedListBox1.GetItemChecked(e.Index),
ButtonState.Checked, ButtonState.Normal))

—

先輩エンジニアからのアドバイス

今回紹介した「オーナードロー」は、最初は少し難しく感じるかもしれません。「なぜ自分で描く必要があるんだ?」と思うでしょう。

しかし、この技術をマスターすると、「リストの中に画像を表示する」「特定の文字だけ赤くする」「データの重要度に応じて背景色を変える」といった、標準機能では不可能なリッチなUIを、爆速で実装できるようになります。

「標準機能でできないから諦める」のではなく、「仕組みを理解して自分でコントロールする」。これこそが、プロの自動化エンジニアへの第一歩です。

まずは、小さなリストから試してみてください。画面が吸い付くようにスクロールする快感を味わえば、きっとこの技術の虜になるはずですよ。応援しています!

タイトルとURLをコピーしました