エディタの背景色を変更したら、他のコントロールも同系色の色にやっぱり変更したいですよね?自作エディタにはエクスプローラーも標準で搭載しているので、そのエクスプローラーの背景色を黒とかに変えてみました。
背景色を変えるまでは良かったのですが、フォーカスが外れた時の文字の色がデフォルトは黒のため、選択しているファイル名が消えてしまう問題がありました。そのため、結局 TreeView についてもオーナードローすることにしました。
オーナードローするとこれまた全部描画する必要があります。また、各ノードの状態(TreeNodeStates)に応じて選択済みかどうか背景色を塗る必要があります。各ノードの状態は OnDrawNode に渡される引数で分かるのですが、実装してみると選択前が一瞬選択状態になったりしてチラついたりしました。そのため、ノードの状態がいまいちわかりにくかったので調べてみました。
TreeView の背景色を黒にした場合の問題点
下記のイメージでは 2.txt の上のノード(1.txt)を選択しているのですが、フォーカスが外れると文字色が黒のため背景色と被って消えてしまいます。
オーナードロー時の各ノードの状態(TreeNodeStates)
TreeView のオーナードローは OwnerDrawText と OwnerDrawAll の2種類ありますが、確か OwnerDrawText は選択した枠の色が変えられないか何か(正確には忘れてしまいました…。)で結局、OwnerDrawAll を採用しました。OwnerDrawAll だとアイコンや開閉ボタンなど全て描画する必要があります。
特に実装していてよくわからなかったのが、各ノードの状態(TreeNodeStates)です。例えば、以下の状態でノードを変更した場合、OnDrawNode で対象ノードがどのような状態に変化するか調べてみました。
1.txt から 2.txt を選択した場合
2.txtの上にマウスカーソルがある状態(No.2まで実行済み)でクリック。No.3からがクリックした一連の処理になります。
No | ファイル名 | TreeNodeStates | 備考 |
---|---|---|---|
1 | 1.txt | Selected, Focused | |
2 | 2.txt | Hot | |
3 | 1.txt | Selected | |
4 | 2.txt | Focused, Hot | |
5 | 1.txt | 0 | |
6 | 2.txt | Selected, Focused, Hot |
2.txt から 1.txt を選択した場合
1.txtの上にマウスカーソルがある状態(No.2まで実行済み)でクリック。No.3からが実際にクリックした一連の処理になります。
No | ファイル名 | TreeNodeStates | 備考 |
---|---|---|---|
1 | 1.txt | Hot | |
2 | 2.txt | Selected, Focused | |
3 | 1.txt | Focused, Hot | |
4 | 2.txt | Selected | |
5 | 1.txt | Selected, Focused, Hot | |
6 | 2.txt | 0 |
結果
私の予想では選択前ノードと選択後ノードの2回、OnDrawNode が呼び出されると思っていたのですが、実際は2回ずつ呼び出されることがわかりました。
クリックした1回目の呼び出しでは、まだ選択状態は変わってなくて選択したノードはフォーカスとマウスカーソルが上にいる状態なんですね。1回ずつ呼び出されると思って実装していたから、チラついたんですね。結局、以下の実装にしました。
マウスオーバーしたノードの判断
TreeNodeStates が 純粋に Hot のノード(TreeView のフォーカスは問わない)
TreeView にフォーカスが有る状態の選択済みノードの判断
TreeView にフォーカスが有る、かつ、MouseDownイベントでクリックしたノード。ノードはTreeView.GetNodeAt メソッドで取得。
TreeView にフォーカスが無い状態の選択済みノードの判断
TreeView にフォーカスが無い、かつ 、TreeNodeStates が 純粋に Selected のノード
おわりに
私の場合、標準のコントールをカスタマイズするとだいたい問題が発生します。で、オーナードローなどで問題が解決できないと自作してしまう習性があるのですが、今回は自作しなくても問題なさそうです。
コメント