摘要:Visual Basic 2005-如何建立一個主控描繪的TreeView控制項
如果您要建立一個主控描繪的 TreeView 控制項,也就是說,想要自行撰寫程式碼來繪製 TreeView 控制項的話,必須將 DrawMode 屬性設定成 TreeViewDrawMode.OwnerDrawAll 或 TreeViewDrawMode.OwnerDrawText,並且替 DrawNode 事件處理常式撰寫程式碼。
圖表 1 所示者是 TreeViewDrawMode 列舉型別的成員及其所代表的意義。
成員名稱 | 說明 |
此為預設值,表示TreeView控制項將由作業系統來繪製。 | |
OwnerDrawAll | 此表示TreeView控制項之節點的所有項目都將由您自行繪製,包括:圖示、核取方塊、加號、減號、以及連接節點的線條。 |
OwnerDrawText | 此表示TreeView控制項之節點的標籤部分將由您自行繪製,至於節點的其他項目則由作業系統來繪製,包括:圖示、核取方塊、加號、減號、以及連接節點的線條。 |
圖表 1
圖表 2
圖表 2 所示者是我們所撰寫之程式範例的執行畫面,此介面中的TreeView 控制項擁有下列特色:
q 如果庫存量低於安全存量,便會在節點之標籤文字的右側額外顯示出一個標記文字「低於安全存量,請盡快補貨。」。
q 使用者除了可以按一下標籤文字來選取節點之外,如果該節點額外顯示出標記文字的話,也可以按一下標記文字「低於安全存量,請盡快補貨。」來選取節點。
q 標記文字「低於安全存量,請盡快補貨。」採用加底線的粗斜體之標楷體字型,而且是黃色的,這些都是我們透過程式碼來自訂的。
q 被選取之節點的背景色是綠色,這也是我們透過程式碼來自訂的。
顯而易見地,本程式示範的TreeView控制項是一個主控描繪的TreeView控制項,其設計技巧說明如下:
q 請如下所示,建立一個給節點之標記文字使用的Font物件:
Private tagFont As New Font("標楷體", 9, _
FontStyle.Bold Or FontStyle.Italic Or FontStyle.Underline)
q 使用者自訂程序 LoadDataToTreeView() 負責將資料庫資料表中的資料填入TreeView控制項中而成為節點。我們以產品名稱作為跟節點,並以其他欄位的內容作為子節點,而在加入子節點時,會判斷「庫存量」欄位的內容是否低於「安全存量」欄位的內容,如果如此的話,便將文字串「低於安全庫存,請盡快補貨。」存入該節點的Tag屬性中:
While drProduct.Read()
' 以產品名稱作為根節點。
rootNode = New TreeNode(drProduct(0).ToString)
TreeView1.Nodes.Add(rootNode)
' 以其他欄位的內容作為子節點。
For i As Integer = 1 To nFieldCount – 1
childNode = New TreeNode( _
drProduct.GetName(i) & ":" & drProduct(i).ToString)
TreeView1.Nodes(nRow).Nodes.Add(childNode)
' 如果庫存量低於安全庫存,則將警示訊息儲
' 存於節點的Tag屬性中。
If drProduct.GetSqlInt16(3) < drProduct.GetSqlInt16(4) Then
TreeView1.Nodes(nRow).Nodes(0).Tag = _
"低於安全庫存,請盡快補貨。"
End If
Next
nRow += 1
End While
q 表單之Load事件處理常式中的下面這一道陳述式,表示要求TreeView控制項採用主控描繪:
TreeView1.DrawMode = TreeViewDrawMode.OwnerDrawText
q 替TreeView控制項的DrawNode事件處理常式撰寫程式碼,以便進行節點的繪製作業:
Private Sub TreeView1_DrawNode(ByVal sender As Object, _
ByVal e As DrawTreeNodeEventArgs) Handles TreeView1.DrawNode
' 繪製被選取之節點的背景色與節點文字。
If (e.State And TreeNodeStates.Selected) <> 0 Then
' 繪製被選取之節點的背景色。如果該節點擁有標記文字
' 「低於安全庫存,請盡快補貨。」的話,NodeBounds方法
' 會使得醒目提示區域擁有足夠的大小來容納它。
e.Graphics.FillRectangle(Brushes.Green, NodeBounds(e.Node))
' 提取節點字型。如果節點字型未被設定,
' 就使用TreeView的字型。
Dim nodeFont As Font = e.Node.NodeFont
If nodeFont Is Nothing Then
nodeFont = CType(sender, TreeView).Font
End If
' 繪製節點文字。
e.Graphics.DrawString(e.Node.Text, nodeFont, _
Brushes.White, e.Bounds.Left - 2, e.Bounds.Top)
Else
e.DrawDefault = True
End If
' 如果存在節點標記,就將它繪製在節點標籤的右側。
If (e.Node.Tag IsNot Nothing) Then
e.Graphics.DrawString(e.Node.Tag.ToString(), tagFont, _
Brushes.Yellow, e.Bounds.Right + 2, e.Bounds.Top)
End If
' 如果節點擁有焦點,便將焦點矩形繪製得夠大
' 以便能夠容納節點標籤文字。
If (e.State And TreeNodeStates.Focused) <> 0 Then
Using focusPen As New Pen(Color.Black)
focusPen.DashStyle = _
System.Drawing.Drawing2D.DashStyle.Dot
Dim focusBounds As Rectangle = NodeBounds(e.Node)
focusBounds.Size = New Size(focusBounds.Width - 1, _
focusBounds.Height - 1)
e.Graphics.DrawRectangle(focusPen, focusBounds)
End Using
End If
End Sub
q 替TreeView控制項的MouseDown事件處理常式撰寫下列程式碼,使得使用者可以按一下標記文字「低於安全庫存,請盡快補貨。」來選取節點:
' 不論使用者按一下節點標籤或節點標記都選取該節點。
Private Sub TreeView1_MouseDown(ByVal sender As Object, _
ByVal e As MouseEventArgs) Handles TreeView1.MouseDown
Dim clickedNode As TreeNode = TreeView1.GetNodeAt(e.X, e.Y)
If NodeBounds(clickedNode).Contains(e.X, e.Y) Then
TreeView1.SelectedNode = clickedNode
End If
End Sub
q 使用者自訂函式NodeBounds能夠傳回所傳遞進來之節點的邊界範圍,包括節點標籤以及節點標記所佔用的區域:
Private Function NodeBounds(ByVal node As TreeNode) As Rectangle
' 將傳回值設定成正常的節點邊界範圍。
Dim bounds As Rectangle = node.Bounds
If (node.Tag IsNot Nothing) Then
' 取得TreeView控制項的Graphics物件並使用
' 它來計算節點標記的顯示寬度。
Dim g As Graphics = TreeView1.CreateGraphics()
Dim tagWidth As Integer = CInt(g.MeasureString( _
node.Tag.ToString(), tagFont).Width) + 6
' 使用計算所得的值來調整節點邊界範圍。
bounds.Offset(tagWidth 2, 0)
bounds = Rectangle.Inflate(bounds, tagWidth 2, 0)
End If
Return bounds
End Function
參考資料:
「Visual Basic 2005程式開發與介面設計秘訣」
「Visual C# 2005程式開發與介面設計秘訣」
章立民研究室