C# TreeView的使用以及节点的拖动

在项目中需要使用TreeView,TreeView中的节点是需要监控的视频站点,当拖动TreeView中的节点到Winform中的显示窗口时,可以实现该节点对应的站点的监控,摄像机转动等功能。

在实现上述功能之前,程序自定义了一个视频终端类(Terminal),用来保存每一个监控站点的信息,以及实现连接摄像头,断开摄像头连接,炫动云台等操作的接口。

实现思路如下

在FormLoad中加载站点信息,以站点名作为对应的节点名,并对每一个节点的Tag属性赋值为该站点对应的Terminal的对象。


加载完所有站点信息后,TreeView的节点在默认情况下是收缩的,如下图所示:

为了能让节点完全展开,不比在界面上逐一点击节点,只需在Form_Load事件中添加下边这句代码即可:

<span style="font-size:18px;"><span style="white-space:pre">	</span>treeView1.ExpandAll();</span>



显示效果如下图:

接下来是实现节点的拖动,将节点拖动到显示窗口,完成将该节点对应的站点与显示界面关联。由于项目设计实验室成果,不方便公开。在此,以拖动节点到显示窗口,在显示窗口完成图片的显示为例。

新建WinForm应用程序,添加TreeView控件和PictureBox控件,将TreeView的AllowDrop属性设置为True,PictureBox也有这一属性,但是在控件的属性列表中看不见这一属性,可在代码中将PictureBox的AllowDrop属性设置为True,需要注意的是编译器不会主动弹出PictureBox的AllowDrop属性,需要手动将代码写完整。将PictureBox的AllowDrop属性置为True的代码如下:

<span style="font-size:18px;"><span style="white-space:pre">	</span>this.pictureBox1.AllowDrop = true;</span>


设计窗体如下:


之后便是手动添加节点,可以在Form_Load事件中完整节点的加载,代码如下

<span style="font-size:18px;">private void Form1_Load(object sender, EventArgs e)
        {
            if (!treeView1.Nodes.ContainsKey("分组1"))
            {
                TreeNode groupNode1 = new TreeNode("分组1");
                groupNode1.Name = "分组1";
                TreeNode rootNode = treeView1.Nodes.Add("分组1");

                if (!rootNode.Nodes.ContainsKey("节点1"))
                {
                    TreeNode TerminalNode1 = new TreeNode();
                    TerminalNode1.Text = "节点1";

                    rootNode.Nodes.Add(TerminalNode1);
                    string filePath1 = @"F:\壁纸图标\theDanceNeverEnd.png";
                    TerminalNode1.Tag = filePath1;
                }

                if (!rootNode.Nodes.ContainsKey("节点2"))
                {
                    TreeNode TerminalNode2 = new TreeNode("节点2");
                    TerminalNode2.Name = "节点2";
                    rootNode.Nodes.Add(TerminalNode2);
                    string filePath2 = @"F:\壁纸图标\cat.jpg";
                    TerminalNode2.Tag = filePath2;
                }
            }

            treeView1.ExpandAll();
        }</span>

这里用代码动态创建了一个根节点,两个子节点,并未每一个子节点的Tag属性分配了一个String类型的值,对应两幅图的路径。

接下来为TreeView添加三个事件,Mouse_Down事件、Item_Drag事件和Drag_Enter事件。Mouse_Down事件不用多说,Item_Drag事件发生在拖动的瞬间,Drag_Enter事件发生在进入控件边缘的瞬间。然后为PixtureBox添加Drag_Enter事件和Drag_Drop事件,Drag_Drop事件发生在拖动结束时。先上代码:

<span style="font-size:18px;">private void treeView1_MouseDown(object sender, MouseEventArgs e)
        {
            TreeNode node = treeView1.GetNodeAt(e.X, e.Y);
            if (node != null)
            {
                treeView1.SelectedNode = node;
            }
        }</span>
<span style="font-size:18px;">private void treeView1_ItemDrag(object sender, ItemDragEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                TreeNode node = treeView1.SelectedNode;
                if (node != null)
                {
                    string path = (node.Tag as string);
                    DoDragDrop(path, DragDropEffects.All);
                }
            }
        }</span>
<span style="font-size:18px;"> private void treeView1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(string)) == true)
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }</span>
<span style="font-size:18px;">private void pictureBox1_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(typeof(string)) == true)
            {
                e.Effect = DragDropEffects.All;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }</span>
<span style="font-size:18px;">private void pictureBox1_DragDrop(object sender, DragEventArgs e)
        {
            string imagePath = (string)(e.Data.GetData(typeof(string)));
            if (imagePath != null)
            {
                Image showImage = Image.FromFile(imagePath);
                pictureBox1.Image = showImage;
                Invalidate();
            }
        }</span>


其中,TreeView的Mouse_Down事件是为了获取选中的目标节点,用到了TreeView的GetNodeAt函数,该函数出入两个座标参数,返回该座标位置的节点。Item_Drag事件调用DoDragDrop方法,开始拖放操作。该方法的声明如下图(参考MSDN):


其中,data为要拖动的数据,allowedEffects为DragDropEffects类型的枚举的值,它表示在拖放操作期间执行的最终效果。DragDropEffects类型的枚举成员如下图:



在Drag_Enter事件中,有用到GetDataPresent函数,该函数确定是否具有指定格式的数据,或者数据是否可以转换为指定格式。MSDN上的重载列表如下图所示:



之后在PictureBox中分别实现了Drag_Enter和Drag_Drop事件,在Drag_Drop事件中,获取拖动的数据,即图像的路径,然后使用Image类的FromFile函数,构造新的Image对象,并将该对象赋值给PictureBox的Image属性,并刷新,拖动节点1和节点2的效果图如下:





之前没有给TreeView添加Mouse_Down事件,直接在Item_Drag事件中使用TreeView.SelectedNode()方法,结果返回的node总是根节点(第一个节点);网上查找资料,有人说是因为要给每一个node的value属性设置 不一样的值,但是在VS2013中我并没有发现这一属性。之后又以为是因为我将节点的加载代码写在Form_Load中的原因,于是有把代码挪到一个Button的事件相应中,发现问题仍然没有解决。后边再研究了一下,原来是selectedNode的默认是TreeView中的第一个节点,所以每一此使用selectedNode之前,需要先改变它,否则就智能得到上一次修改的值或者是默认值。






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章