.NET TIPS TreeViewコントロールで効率的にツリーを構築するには?デジタルアドバンテージ 一色 政彦2005/02/04 |
|
|
「TIPS:TreeViewコントロールへ項目を追加するには?」では、TreeViewコントロールでツリーを構築するために、複数のツリーのデータ項目(ノード)をまとめて登録する方法や1つずつ追加する方法を紹介した。
特に複数のノードをまとめて追加するツリー構築手法は、そのツリー形状が固定的な場合には最も効率がよい。しかし例えばレジストリ・エディタやエクスプローラのように、ツリー階層が非常に深く、またその深さが不定の場合、ツリー全体の項目を最初にすべて追加しようとすると、その処理に時間がかかってしまい、アプリケーションのパフォーマンスが低下する可能性がある。
そこで、本稿では適切なタイミングで必要なだけのツリー・ノードを追加する方法を紹介する。これにより、ツリー全体の構築が効率的になる。
適切なタイミングで必要なだけのツリー・ノードを追加する方法
TreeViewコントロールに最も効率的にノードを登録できるタイミングは、TreeViewコントロールのBeforeExpandイベントが発行されたときである。このBeforeExpandイベントは、ノードが展開される直前に発行される。
このイベントのタイミングで展開されようとしているノードに子ノードを追加すればよいのだが、それだけではそれぞれの子ノードが展開可能かどうか(子ノードを持っているかどうか)を示すことができない(ノードに子ノードがあり展開可能な場合には、それを示す「+」マークがノードの左横に表示される。ただし、TreeViewコントロールのShowPlusMinusプロパティがTrueの場合のみ。既定ではTrue)。このため、あるノードが展開されるときには、それより2段階下のノード(以降、孫ノード)まで追加しておかなければないということになる。
言葉の説明だけではなかなかイメージしづらいので、具体的な例を使って説明することにしよう。
ここでは、ツリー全体が次のような構造であるとする。
例えば上記のツリーの「食べ物」のノードを展開しようとしている場合、「果物」と「野菜」の子ノードを追加しているだけでは、「果物」の左横に展開可能な「+」マークが表示されない。このため「食べ物」のノードが展開される直前には、「果物」に対して「りんご」と「みかん」(「食べ物」から見ると、孫ノード)が追加されていなければならないのである。
ただし、BeforeExpandイベントはノードが展開されるたびに発行されるので、同じノードが何度も登録されないようにするために、何らかの手段で子ノードがすでに追加済みかどうかを管理する必要がある。
●子ノードの管理機能を持つ独自のTreeNodeExクラス
そこで本稿では、ノードを表すTreeNodeクラス(System.Windows.Forms名前空間)を継承して、そのような管理機能をノード自身に持たせることにする。このようにして作成したTreeNodeExクラスを以下に示す。
|
|
子ノードが追加済みかどうかを管理する機能を持つTreeNodeExクラス(C#) |
|
|
子ノードが追加済みかどうかを管理する機能を持つTreeNodeExクラス(VB.NET) |
上記のTreeNodeExオブジェクトを、ツリーに追加するノード・オブジェクトとして、TreeNodeオブジェクトの代わりに使えばよい。
効率的にツリーが構築されるサンプル・プログラム
それでは、実際にBeforeExpandイベントでノードを追加するプログラムを作成してみよう。このサンプル・プログラムは、レジストリ・キーのツリー構造を表示するプログラムだ。
以下の画面は、そのサンプル・プログラムを実行しているところである。
TreeViewコントロールのサンプル・プログラムの実行結果 |
●BeforeExpandイベント・ハンドラによる孫ノードの追加
上のサンプル・プログラムのTreeViewコントロールのツリー・ノードを実際に追加している部分のコードを以下に抜粋して示す。
|
|
TreeViewコントロールにノードを効率的に追加するサンプル・コード(C#) | |
|
|
TreeViewコントロールにノードを効率的に追加するサンプル・コード(VB.NET) | |
まず初期表示として(フォームのLoadイベント・ハンドラで)、RefreshTreeViewメソッドによりあらかじめ基本となるノードを追加する。そして、BeforeExpandイベントのイベント・ハンドラであるtreeView1_BeforeExpandメソッドで順次、必要なだけのノードを追加していく、という内容のコードになっている。
RefreshTreeViewメソッドでは、TreeViewコントロールのNodesプロパティのAddメソッドにより、ツリーにノードを追加している。注意点としては、本稿では、追加するすべてのノードを前述のTreeNodeExオブジェクトにしているということだ。なおこのNodesプロパティのAddメソッドは、実際にはノードのコレクションを示すTreeNodeCollectionクラス(System.Windows.Forms名前空間)のメソッドである。詳しくは前掲のTIPSを参照してほしい。
treeView1_BeforeExpandメソッドでは、そのパラメータに引き渡されるTreeViewCancelEventArgsオブジェクト(System.Windows.Forms名前空間)のNodeプロパティ(=「展開されようとしているノード」)のNodesプロパティからすべての「子ノード」を取得し、それぞれの子ノードが所有するサブ・キーを取得して、子ノードのNodesプロパティ(これも実体はTreeNodeCollectionオブジェクト)のAddメソッドにより、そのサブ・キーを子ノードの下に(「孫ノード」として)追加している。
そのサブ・キーの取得では、RegistryUtilityクラスのGetSubKeysメソッドを利用している。RegistryUtilityクラスはレジストリからキー情報を得るために自作した本稿独自のクラスで、そのGetSubKeysメソッドはパラメータに指定したレジストリ・キー・パスの配下にあるすべてのサブ・キー名を文字列配列として返すメソッドである。また、レジストリ・キー・パスはGetPathFromNodeメソッドにより取得している。GetPathFromNodeメソッドは、パラメータに指定されたノードのパスを文字列として返すメソッドである。
なおコードの実行時には、RefreshTreeViewメソッドの最後にTreeViewコントロールのTopNodeプロパティのExpandメソッドを呼び出しているため、ツリーに最初に追加した「マイ コンピュータ」というノードが展開される。この場合にもBeforeExpandイベントが発行されるので、初期の状態ですでに「マイコンピュータ」の子ノード(例えば、「HKEY_LOCAL_MACHINE」)に、そのサブ・キーのノード(「マイコンピュータ」から見ると、孫ノード)が追加されることになる。
後はクリックなどによりノードを展開するたびに、そこで必要となるノードが追加され、ツリー全体が徐々に構築されることになる。
カテゴリ:Windowsフォーム 処理対象:TreeViewコントロール 使用ライブラリ:TreeNodeクラス(System.Windows.Forms名前空間) 使用ライブラリ:TreeNodeCollectionクラス(System.Windows.Forms名前空間) 使用ライブラリ:TreeViewCancelEventArgsクラス(System.Windows.Forms名前空間) 関連TIPS:TreeViewコントロールへ項目を追加するには? |
「.NET TIPS」 |
- 第2回 簡潔なコーディングのために (2017/7/26)
ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている - 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう - 第1回 明瞭なコーディングのために (2017/7/19)
C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える - Presentation Translator (2017/7/18)
Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
|
|