在实现上述功能之前,程序自定义了一个视频终端类(Terminal),用来保存每一个监控站点的信息,以及实现连接摄像头,断开摄像头连接,炫动云台等操作的接口。
实现思路如下:在FormLoad中加载站点信息,以站点名作为对应的节点名,并对每一个节点的Tag属性赋值为该站点对应的Terminal的对象。
加载完所有站点信息后,TreeView的节点在默认情况下是收缩的,如下图所示:
为了能让节点完全展开,不比在界面上逐一点击节点,只需在Form_Load事件中添加下边这句代码即可:
treeView1.ExpandAll();
接下来是实现节点的拖动,将节点拖动到显示窗口,完成将该节点对应的站点与显示界面关联。由于项目设计实验室成果,不方便公开。在此,以拖动节点到显示窗口,在显示窗口完成图片的显示为例。
新建WinForm应用程序,添加TreeView控件和PictureBox控件,将TreeView的AllowDrop属性设置为True,PictureBox也有这一属性,但是在控件的属性列表中看不见这一属性,可在代码中将PictureBox的AllowDrop属性设置为True,需要注意的是编译器不会主动弹出PictureBox的AllowDrop属性,需要手动将代码写完整。将PictureBox的AllowDrop属性置为True的代码如下:
this.pictureBox1.AllowDrop = true;
之后便是手动添加节点,可以在Form_Load事件中完整节点的加载,代码如下
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();
}
接下来为TreeView添加三个事件,Mouse_Down事件、Item_Drag事件和Drag_Enter事件。Mouse_Down事件不用多说,Item_Drag事件发生在拖动的瞬间,Drag_Enter事件发生在进入控件边缘的瞬间。然后为PixtureBox添加Drag_Enter事件和Drag_Drop事件,Drag_Drop事件发生在拖动结束时。先上代码:
private void treeView1_MouseDown(object sender, MouseEventArgs e)
{
TreeNode node = treeView1.GetNodeAt(e.X, e.Y);
if (node != null)
{
treeView1.SelectedNode = node;
}
}
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);
}
}
}
private void treeView1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)) == true)
{
e.Effect = DragDropEffects.All;
}
else
{
e.Effect = DragDropEffects.None;
}
}
private void pictureBox1_DragEnter(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)) == true)
{
e.Effect = DragDropEffects.All;
}
else
{
e.Effect = DragDropEffects.None;
}
}
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();
}
}
其中,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之前,需要先改变它,否则就智能得到上一次修改的值或者是默认值。