C# TreeViewのスクロールバーを移動させたときのイベントは?
treeview-scrollbar-event
C# TreeViewのスクロールバーを移動させたとき、これに伴ってTreeViewの右側にあるパネルに描画する内容を変化させるというプログラムを書かなければならなくなりました。さてTreeViewのスクロールバーを移動させたときのイベントというのはあるのでしょうか? プロパティをみたところ、それっぽいものは存在しません。
そこでTreeViewを継承してWndProcメソッドをオーバーライドすることにしました。今回はスクロールバーが動いたことがわかればそれでよいのでイベントハンドラに渡す引数は中身のないEventArgsオブジェクトです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
public class TreeViewEx : TreeView { public TreeViewEx() { } const int WM_HSCROLL = 0x114; const int WM_VSCROLL = 0x115; public event EventHandler Scroll; protected override void WndProc(ref System.Windows.Forms.Message m) { switch (m.Msg) { // スクロールバーが縦に動いた場合 case WM_VSCROLL: Scroll?.Invoke(this, new EventArgs()); break; // スクロールバーが横に動いた場合 case WM_HSCROLL: Scroll?.Invoke(this, new EventArgs()); break; } base.WndProc(ref m); } } |
それからついでにTreeViewの全ノードを取得するメソッドも追加してみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
public class TreeViewEx : TreeView { public List<TreeNode> GetAllNodes() { List<TreeNode> treeNodes = new List<TreeNode>(); if (this.Nodes.Count == 0) return treeNodes; TreeNode root = this.Nodes[0]; TreeNode curNode = root; treeNodes.Add(curNode); bool needChild = true; while (true) { if (needChild && curNode.FirstNode != null) { curNode = curNode.FirstNode; treeNodes.Add(curNode); } else if (curNode.NextNode != null) { curNode = curNode.NextNode; treeNodes.Add(curNode); needChild = true; } else if (curNode.Parent != null) { curNode = curNode.Parent; needChild = false; } else return treeNodes; } } } |
フォームにTreeViewExをドラッグアンドドロップしてイベントハンドラを追加します。
なにをしようとしているのかというと右側にあるパネルのうえにTreeNodeのラベルを描画しようとしています。TreeViewExのスクロールバーを移動させたり、アイテムを展開したり縮小させたときもTreeViewExのアイテムが存在するY座標と同じ位置にTreeNodeのラベルが描画されるようにしようとしているのです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public partial class Form1 : Form { public Form1() { InitializeComponent(); this.DoubleBuffered = true; panelEx1.Paint += Panel1_Paint; // TreeViewがスクロールされたりアイテムが展開されたり縮小されたり選択されたときの処理は // 同じなので同じイベントハンドラであるPanelInvalidateを追加している treeViewEx1.Scroll += PanelInvalidate; treeViewEx1.AfterCollapse += PanelInvalidate; treeViewEx1.AfterExpand += PanelInvalidate; treeViewEx1.AfterSelect += PanelInvalidate; } private void PanelInvalidate(object sender, EventArgs e) { panelEx1.Invalidate(); } Font PanelTextFont = null; private void Panel1_Paint(object sender, PaintEventArgs e) { // PanelInvalidateが実行されたら 右側のパネルにTreeNodeのラベルを描画する // TreeNodeのY座標とTreeNodeのラベルを描画されるY座標は同じになる List<TreeNode> treeNodes = treeViewEx1.GetAllNodes(); foreach (TreeNode node in treeNodes) { // 折りたたまれて見えないTreeNodeのラベルは描画しない if (!node.IsVisible) continue; if(PanelTextFont == null) PanelTextFont = new Font(treeViewEx1.Font, FontStyle.Bold); Rectangle rectangle = node.Bounds; e.Graphics.DrawString(node.Text, PanelTextFont, Brushes.Black, 10, rectangle.Y); } } } |
さて、こんなものをつくってどうしようというのでしょうか? 今後使うことになるので作っているのです。