Visual Basic 2005-如何建立一個主控描繪的TreeView控制項

摘要:Visual Basic 2005-如何建立一個主控描繪的TreeView控制項

如果您要建立一個主控描繪的 TreeView 控制項,也就是說,想要自行撰寫程式碼來繪製 TreeView 控制項的話,必須將 DrawMode 屬性設定成 TreeViewDrawMode.OwnerDrawAll TreeViewDrawMode.OwnerDrawText,並且替 DrawNode 事件處理常式撰寫程式碼。

圖表 1 所示者是 TreeViewDrawMode 列舉型別的成員及其所代表的意義。

成員名稱

說明

Normal

此為預設值,表示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程式開發與介面設計秘訣」

章立民研究室 2007/1/9