在實現上述功能之前,程序自定義了一個視頻終端類(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之前,需要先改變它,否則就智能得到上一次修改的值或者是默認值。