【问题标题】:Custom treeview VB.net自定义树视图 VB.net
【发布时间】:2019-11-14 08:55:54
【问题描述】:

我希望在 VB.net 中创建一个自定义树视图控件,我需要做的是有一个标准的树视图控件来显示系统文件结构,但在文件夹/文件的右侧有一个额外的图标仅在将鼠标悬停在节点上时出现的名称。因此,例如,如果我将鼠标悬停在如图所示的文件夹 Sup2 上,则会出现橙色图标

我已经进行了一些研究,据我所知,我必须重写 onpaint 事件才能实现这一点,但我不确定如何做到这一点。我还需要为那个新的橙色图标添加一个 onclick 事件。

【问题讨论】:

  • 您可以使用标准的TreeView 执行此操作,方法是将DrawMode 设置为Normal 以外的其他值,然后处理DrawNode 事件。您还可以创建自己的类,在内部执行相同的操作,覆盖 OnDrawNode 而不是处理事件。

标签: vb.net treeview


【解决方案1】:

这个不专业,但值得一试..

我创建了一个继承自 Treeview 控件的类并覆盖了构造函数 - 更改了默认宽度和高度,将 DrawMode 设置为 TreeViewDrawMode.OwnerDrawText

接下来,我处理了TreeView.DrawNode 事件,使用PictureBox 显示图像并根据当前突出显示的项目更改其位置。

我还处理了PictureBoxClick 事件。在该事件下,您可以对突出显示的节点执行任何操作。

我使用来自My.Resources 的图像用于ImageList.Images(0)PictureBox.Image

Class Form1
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim trv As New MyTreeView
        trv.Nodes.Add("Suppliers")
        trv.Nodes(0).Nodes.Add("Sup 1")
        trv.Nodes(0).Nodes.Add("Sup 2")
        trv.Nodes(0).Nodes.Add("Sup 3")
        trv.Nodes(0).Nodes.Add("Sup 4")
        trv.Nodes(0).Nodes.Add("Sup 5")
        Controls.Add(trv)
    End Sub
End Class

'Class Starts Here
Public Class MyTreeView
    Inherits TreeView
    WithEvents myImage As PictureBox
    Dim activeItem As TreeNode    'Variable to store active TreeNode
    Public Sub New()
        MyBase.New()              'Call the base class constructor
        'And set some values
        Height = 300
        Width = 300
        Location = New Point(50, 50)
        DrawMode = TreeViewDrawMode.OwnerDrawText       'Very neccesary
        AddHandler DrawNode, AddressOf MyTreeViewDrawNode   
        'Add event handlers
        AddHandler AfterCollapse, AddressOf MyTreeViewCollapsed
        'Set HotTracking event to true to allow for MouseHover
        HotTracking = True
        ImageList = new ImageList
        ImageList.Images.Add(My.Resources.FolderImage)
        ImageIndex = 0

        Font = New Font(Font.FontFamily, 10)
        'Initialize picturebox
        myImage = New PictureBox() With
        {
            .Image = My.Resources.editPencilImage,
            .SizeMode = PictureBoxSizeMode.Zoom,
            .Size = New Size(10, 10),
            .Visible = False
        }
        Controls.Add(myImage)
    End Sub

    Private Sub MyTreeViewCollapsed(sender As Object, e As TreeViewEventArgs)
        myImage.Visible = False
    End Sub

    Sub ImageClicked(sender As Object, e As EventArgs) Handles myImage.Click
        If (Not activeItem Is Nothing) Then
            MessageBox.Show("Clicked Item - " & activeItem.Text)
        End If
    End Sub

    Private Sub MyTreeViewDrawNode(sender As Object, e As DrawTreeNodeEventArgs)
        e.DrawDefault = True
        If (e.State = TreeNodeStates.Hot) Then
            myImage.Visible = True
            activeItem = e.Node
            Dim tmpSize = TextRenderer.MeasureText(e.Node.Text, Font)
            myImage.Location = New Point(e.Node.Bounds.Location.X + tmpSize.Width, e.Node.Bounds.Location.Y)
        End If
    End Sub
End Class

【讨论】:

    【解决方案2】:

    我认为下面的例子会给你一些提示和技巧。

    Option Explicit On
    
    Imports System.Windows.Forms
    Imports System.Drawing
    Imports System.Drawing.Drawing2D
    Imports System.Drawing.Text
    Imports System.Runtime.InteropServices
    
    Public Class TreeViewEx
        Inherits TreeView
    
    #Region "API"
    
        Private Const TVM_SETEXTENDEDSTYLE As Integer = &H1100 + 44
        Private Const TVS_EX_DOUBLEBUFFER As Integer = &H4
    
        <DllImport("user32.dll")>
        Private Shared Function SendMessage(ByVal hWnd As IntPtr,
                                            ByVal msg As Integer,
                                            ByVal wp As IntPtr,
                                            ByVal lp As IntPtr) As IntPtr
        End Function
    
    #End Region
    
    #Region "Private Fields"
    
        Private ReadOnly RightImage As Bitmap
        Private ReadOnly NSF As StringFormat
    
        Private HoverNode As TreeNode
        Private RightImageRect As Rectangle
    
    #End Region
    
    #Region "Constructors"
    
        Sub New()
            DrawMode = TreeViewDrawMode.OwnerDrawText
            RightImage = New Bitmap(My.Resources.Modify)
            NSF = New StringFormat With {
                .Alignment = StringAlignment.Near,
                .LineAlignment = StringAlignment.Center,
                .Trimming = StringTrimming.EllipsisCharacter,
                .FormatFlags = StringFormatFlags.NoWrap
            }
        End Sub
    
    #End Region
    
    #Region "Paint"
    
        Protected Overrides Sub OnDrawNode(e As DrawTreeNodeEventArgs)
            MyBase.OnDrawNode(e)
    
            If e.Node Is Nothing Then Return
    
            Dim rect As Rectangle = e.Bounds : rect.Inflate(0, 1)
    
            If Not ClientRectangle.IntersectsWith(rect) Then
                Return
            End If
    
            Dim G As Graphics = e.Graphics
    
            G.SmoothingMode = SmoothingMode.HighQuality
            G.TextRenderingHint = TextRenderingHint.ClearTypeGridFit
    
            'Option1: If you want to draw different background color for the selected node.
            'If (e.State And TreeNodeStates.Selected) = TreeNodeStates.Selected Then
            '    Using br As New SolidBrush(Color.LightSteelBlue) '<- suit yourself!
            '        G.FillRectangle(br, rect)
            '    End Using
            'Else
            '    Using br As New SolidBrush(If(e.Node.BackColor.Equals(Color.Empty), BackColor, e.Node.BackColor))
            '        G.FillRectangle(br, rect)
            '    End Using
            'End If
    
            'Option2: If you don't want Option1.
            Using br As New SolidBrush(If(e.Node.BackColor.Equals(Color.Empty), BackColor, e.Node.BackColor))
                G.FillRectangle(br, rect)
            End Using
    
            Using br As New SolidBrush(If(e.Node.ForeColor.Equals(Color.Empty), ForeColor, e.Node.ForeColor))
                G.DrawString(e.Node.Text, If(e.Node.NodeFont, Font), br, rect, NSF)
            End Using
    
            If ReferenceEquals(e.Node, HoverNode) Then
                RightImageRect = New Rectangle(rect.Right + 5,
                                               rect.Y + ((rect.Height - RightImage.Height) / 2),
                                               rect.Height - 4, rect.Height - 4)
                G.DrawImage(RightImage,
                            RightImageRect,
                            New Rectangle(0, 0, RightImage.Width, RightImage.Height),
                            GraphicsUnit.Pixel)
            End If
        End Sub
    
    #End Region
    
    #Region "Other Events"
    
        'You need this to reduce the flickering.
        Protected Overrides Sub OnHandleCreated(ByVal e As EventArgs)
            SendMessage(
                Handle,
                TVM_SETEXTENDEDSTYLE,
                IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER),
                IntPtr.op_Explicit(TVS_EX_DOUBLEBUFFER)
                )
            MyBase.OnHandleCreated(e)
        End Sub
    
        Protected Overrides Sub OnMouseMove(e As MouseEventArgs)
            MyBase.OnMouseMove(e)
    
            Dim node = GetNodeAt(e.Location)
    
            If node IsNot Nothing Then
                'Avoid unnecessary Invalidate() calls.
                If Not ReferenceEquals(node, HoverNode) Then
                    HoverNode = node
                    Invalidate()
                End If
            Else
                'Avoid unnecessary Invalidate() calls.
                If HoverNode IsNot Nothing Then
                    HoverNode = Nothing
                    Invalidate()
                End If
            End If
        End Sub
    
        Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
            MyBase.OnMouseDown(e)
    
            If e.Button = MouseButtons.Left AndAlso
                RightImageRect.Contains(e.Location) Then
                'Notify the container to do something.
                OnEditButtonClicked()
            End If
        End Sub
    
        Protected Overrides Sub OnMouseLeave(e As EventArgs)
            MyBase.OnMouseLeave(e)
            Invalidate()
        End Sub
    
        Protected Overrides Sub Dispose(disposing As Boolean)
            MyBase.Dispose(disposing)
            If disposing Then
                RightImage.Dispose()
                NSF.Dispose()
            End If
        End Sub
    
    #End Region
    
    #Region "Custom Events"
    
        Public Class EditButtonClickArgs
            Inherits EventArgs
    
            Public Property Node As TreeNode
    
            Sub New(node As TreeNode)
                Me.Node = node
            End Sub
        End Class
    
        ''' <summary>
        ''' Raised when the right image is clicked.
        ''' </summary>
        Public Event EditButtonClicked As EventHandler(Of EditButtonClickArgs)
    
        ''' <summary>
        ''' Raises the <see cref="EditButtonClicked"/> events.
        ''' </summary>
        Protected Overridable Sub OnEditButtonClicked()
            RaiseEvent EditButtonClicked(Me, New EditButtonClickArgs(HoverNode))
        End Sub
    
    #End Region
    
    End Class
    

    在包含新 TreeViewEx 控件的 Form 中,您可以处理 EditButtonClicked 来做必要的事情:

    Public Class Form1
        Inherits Form
    
        Private Sub TreeViewEx1_EditButtonClicked(sender As Object, e As TreeViewEx.EditButtonClickArgs) Handles TreeViewEx1.EditButtonClicked
            'Do something with the e.Node
        End Sub
    
    End Class
    

    这是一个快速演示:

    祝你好运。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-16
      • 1970-01-01
      相关资源
      最近更新 更多