如果您要建立一个主控描绘的
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)
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
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
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
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
' 不论用户按一下节点卷标或节点标记都选取该节点。
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
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程序开发与界面设计秘诀》
《Visual Basic 2005程序开发与界面设计秘诀》
《Visual C# 2005程序开发与界面设计秘诀》