« カスタムツリービューの基本的な使い方(その9~階層構造 – 表示) | WinMerge 7-Zip Plugin (for 7-Zip 4.57) » |
カスタムツリービューの基本的な使い方(その10~階層構造 – フォルダ開閉)
「その9~階層構造 – 表示」で作成したツリーは表示のみであったが、今回フォルダの開閉機能を実装する。
フォルダの開閉機能
フォルダの行をダブルクリックしたり、フォルダ上でEnterキーを押下したりすると、 nsITreeView#toggleOpenState メソッドが呼び出される。
toggleOpenState では、 _visibleData の中の引数 index に対応するアイテムの open プロパティを変更し、 _buildVisibleData を使って _visibleData を再構築する。
さらに、フォルダ開閉に伴い行数に変化が生じたため、 nsITreeBoxObject#rowCountChanged を呼び出す必要がある。
rowCountChanged の第1引数は変化が生じた最初の行番号、第2引数は行数の増減値である。
例えば0行目の「Red」フォルダを閉じると、そのフォルダのすぐ下の4行が消滅するため、 rowCountChanged(1, -4) となる。
これでめでたく完了、と思いきやフォルダ上でEnterキーを押した場合にフォルダの開閉状態を示す +/- 記号に変化が無いという問題があった。
そこで、 nsITreeBoxObject#invalidateRow によってその行だけを再描画する必要がある。
toggleOpenState: function(index) { var lastRowCount = this.rowCount; // change |open| property this._visibleData[index].open = !this._visibleData[index].open; this._buildVisibleData(); this._treeBoxObject.rowCountChanged(index + 1, this.rowCount - lastRowCount); // need this to update the -/+ sign when called by pressing enter key this._treeBoxObject.invalidateRow(index); },
例えば「Yellow」フォルダをダブルクリックして開いたとすると、再構築された _visibleData は下表に示すような配列となる。
item#2 の水色で着色した箇所が、フォルダを開いた際に変更された open プロパティである。
また、緑色で着色した item#9 と item#C が、フォルダを開いたことによって新たに追加されたアイテムである。
id | type | name | parent | open | empty | level | hasNext | parentIndex | |
---|---|---|---|---|---|---|---|---|---|
[0] | item#1 | 2 | Red | root | true | false | 0 | true | -1 |
[1] | item#5 | 1 | Apple | item#1 | 1 | true | 0 | ||
[2] | item#6 | 1 | Cherry | item#1 | 1 | true | 0 | ||
[3] | item#7 | 3 | item#1 | 1 | true | 0 | |||
[4] | item#8 | 1 | Peach | item#1 | 1 | false | 0 | ||
[5] | item#2 | 2 | Yellow | root | true | false | 0 | true | -1 |
[6] | item#9 | 2 | Citrus | item#2 | false | false | 1 | true | 5 |
[7] | item#C | 1 | Banana | item#2 | 1 | false | 5 | ||
[8] | item#3 | 3 | root | 0 | true | -1 | |||
[9] | item#4 | 2 | Blue | root | false | true | 0 | false | -1 |
応用例~シングルクリックでのフォルダの開閉~
上記で実装したように、通常フォルダはダブルクリック時にフォルダの開閉が可能だが、ブックマークツリーのようにシングルクリックでもフォルダも開閉を可能にする。
まず、 fruits.xul の tree または treechildren 要素へ onclick 属性を追加する。
<tree id="fruitsTree" flex="1" onclick="handleClick(event);">
先ほど onclick 属性で追加したイベントハンドラである handleTreeClick 関数を実装する。
その際、クリックした位置のアイテムを取得するために nsITreeBoxObject#getCellAt を使ってヒットテストを行う。
nsITreeBoxObjcet#getCellAt メソッドは、第1引数、第2引数で指定した座標にセルがあるかを判定し、セルがある場合は第3引数、第4引数、第5引数に引き渡したオブジェクトの value プロパティにそれぞれ行番号、列を表す nsITreeColumn オブジェクト、セル内の部位を表す文字列(””, “cell”, “text”, “image”, “twisty” のうちのいずれか)がセットされる。
今回は第1引数、第2引数にはクリックした時のマウスポインタ位置を渡して、返ってきた第3引数、第5引数の value プロパティを調べ、ツリーカラムやツリー内の余白部分などの非セル部分をクリックした場合 (row.value == -1)、フォルダ左端の+/-記号をクリックした場合 (obj.value == twisty”) を除外する。クリックした位置がツリーのセルであり、なおかつその行がフォルダである場合のみ、 nsITreeView#toggleOpenState でフォルダの開閉を行う。
//////////////////////////////////////////////////////////////// // Event Handlers function handleClick(event) { if (event.button != 0) return; // hit test var row = {}, obj = {}; gFruitsTreeView._treeBoxObject.getCellAt(event.clientX, event.clientY, row, {}, obj); if (row.value == -1 || obj.value == "twisty") return; if (gFruitsTreeView.isContainer(row.value)) gFruitsTreeView.toggleOpenState(row.value); }
関連記事
- カスタムツリービューの基本的な使い方(その1~表示)
- カスタムツリービューの基本的な使い方(その2~追加・削除)
- カスタムツリービューの基本的な使い方(その3~インライン編集)
- カスタムツリービューの基本的な使い方(その4~並び替え)
- カスタムツリービューの基本的な使い方(その5~ドラッグ&ドロップ)
- カスタムツリービューの基本的な使い方(その6~複数列ツリー)
- カスタムツリービューの基本的な使い方(その7~プログレスバー)
- カスタムツリービューの基本的な使い方(その8~チェックボックス)
- カスタムツリービューの基本的な使い方(その9~階層構造 – 表示)
- カスタムツリービューの基本的な使い方(その10~階層構造 – フォルダ開閉)