将按钮添加到 TreeNode

问题描述

美好的一天。 有一个自定义控件,为每个Node添加一个按钮

Imports System.Windows.Forms.VisualStyles

Public Class CustomTreeView
    Inherits TreeView

    Private buttonRect As New Rectangle(80,2,50,26)
    Private ReadOnly stringFormat As StringFormat

    Public Sub New()
        SetStyle(ControlStyles.OptimizedDoubleBuffer,True)

        DrawMode = TreeViewDrawMode.OwnerDrawText
        ShowLines = False
        FullRowSelect = True
        ItemHeight = 30

        stringFormat = New StringFormat With {
            .Alignment = Stringalignment.Near,.LineAlignment = Stringalignment.Center
        }
    End Sub

    Protected Overrides Sub OnDrawNode(ByVal e As DrawTreeNodeEventArgs)
        e.Graphics.DrawString(e.Node.Text,Me.Font,New SolidBrush(Me.ForeColor),e.Bounds,stringFormat)
        ButtonRenderer.DrawButton(e.Graphics,New Rectangle(e.Node.Bounds.Location + New Size(buttonRect.Location),buttonRect.Size),"btn",True,If(e.Node.Tag IsNot nothing,CType(e.Node.Tag,PushButtonState),PushButtonState.normal))
    End Sub

    Protected Overrides Sub OnNodeMouseClick(ByVal e As TreeNodeMouseClickEventArgs)
        Select Case e.Node.Tag
            Case nothing,Is <> PushButtonState.pressed
                Return
        End Select
        e.Node.Tag = PushButtonState.normal
        MessageBox.Show(e.Node.Text & " clicked")
        ' force redraw
        e.Node.Text = e.Node.Text
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
        Dim tnode As TreeNode = GetNodeAt(e.Location)
        If tnode Is nothing Then
            Return
        End If

        Dim btnRectAbsolute As New Rectangle(tnode.Bounds.Location + New Size(buttonRect.Location),buttonRect.Size)
        If btnRectAbsolute.Contains(e.Location) Then
            tnode.Tag = PushButtonState.pressed
            tnode.Text = tnode.Text
        End If
    End Sub
End Class

告诉我如何只在第一个(主要)点头时显示按钮? 以及如何,当您单击此按钮时,不显示消息,而是调用某个过程?

解决方法

没有内置按钮树节点。但是您可以自己创建一个带有按钮的自定义树节点。此自定义树节点继承自 TreeNode。为了提高可扩展性,我们为具有 DrawNode 方法的树节点声明了一个接口:

Imports System.Windows.Forms.VisualStyles

Public Interface ICustomDrawTreeNode
    Sub DrawNode(ByVal e As DrawTreeNodeEventArgs,buttonState As PushButtonState)
End Interface

我们还创建了一个模块,其中包含在自定义树视图和自定义树节点中使用的一些设置

Module Settings
    Public ReadOnly ButtonRect As New Rectangle(80,2,50,26)

    Public ReadOnly TextStringFormat = New StringFormat() With {
        .Alignment = StringAlignment.Near,.LineAlignment = StringAlignment.Center,.FormatFlags = StringFormatFlags.NoClip Or StringFormatFlags.FitBlackBox Or StringFormatFlags.LineLimit
    }

End Module

然后我们可以实现一个像这样的按钮节点

Imports System.Windows.Forms.VisualStyles

Public Class ButtonTreeNode
    Inherits TreeNode
    Implements ICustomDrawTreeNode

    Private ReadOnly buttonText As String

    Public Sub New(text As String,buttonText As String)
        MyBase.New(text)

        Me.buttonText = buttonText
    End Sub

    Public Sub DrawNode(e As DrawTreeNodeEventArgs,buttonState As PushButtonState) _
        Implements ICustomDrawTreeNode.DrawNode

        Dim font As Font = e.Node.TreeView.Font

        ' Draw Text to the left of the button
        Dim rect As Rectangle = New Rectangle(
            e.Node.Bounds.Location,New Size(Settings.ButtonRect.Left,e.Bounds.Height))
        e.Graphics.DrawString(e.Node.Text,font,Brushes.Black,rect,Settings.TextStringFormat)

        ' Draw the button
        rect = New Rectangle(
            e.Node.Bounds.Location + Settings.ButtonRect.Location,Settings.ButtonRect.Size)
        ButtonRenderer.DrawButton(e.Graphics,buttonText,True,buttonState)
    End Sub
End Class

它有一个 Private ReadOnly buttonText As String 来存储按钮的文本。普通节点文本和按钮文本在ButtonTreeNode的构造函数中传递:

Public Sub New(text As String,buttonText As String)

DrawNode 方法将被调用为 CustomTreeView 中的 OnDrawNode


CustomTreeView 中,我声明了一个 NodeButtonClick 事件,当单击节点的按钮时将引发该事件。然后您可以在表单中处理此事件。当您在设计器中选择 CustomTreeView 时,此新事件将出现在事件的“操作”部分。

Imports System.ComponentModel
Imports System.Windows.Forms.VisualStyles

Public Class CustomTreeView
    Inherits TreeView

    <Category("Action")>
    Public Event NodeButtonClick(e As TreeNodeMouseClickEventArgs)

    Private _isButtonPressed As Boolean

    Public Sub New()
        SetStyle(ControlStyles.OptimizedDoubleBuffer,True)
        DrawMode = TreeViewDrawMode.OwnerDrawText
        ShowLines = False
        FullRowSelect = True
        ItemHeight = 30
    End Sub

    Protected Overrides Sub OnDrawNode(e As DrawTreeNodeEventArgs)
        Dim customDrawNode As ICustomDrawTreeNode = TryCast(e.Node,ICustomDrawTreeNode)
        If customDrawNode Is Nothing Then ' Normal text node.
            e.Graphics.DrawString(e.Node.Text,Font,e.Node.Bounds,Settings.TextStringFormat)
        Else
            customDrawNode.DrawNode(e,If(_isButtonPressed,PushButtonState.Pressed,PushButtonState.Normal))
        End If
    End Sub

    Protected Overrides Sub OnNodeMouseClick(e As TreeNodeMouseClickEventArgs)
        If _isButtonPressed Then
            _isButtonPressed = False
            Refresh()
            Dim buttonNode = TryCast(e.Node,ButtonTreeNode)
            If buttonNode IsNot Nothing Then
                RaiseEvent NodeButtonClick(e)
            End If
        End If
    End Sub

    Protected Overrides Sub OnMouseDown(e As MouseEventArgs)
        Dim buttonNode = TryCast(GetNodeAt(e.Location),ButtonTreeNode)
        If buttonNode IsNot Nothing Then
            Dim btnRectAbsolute As New Rectangle(
                buttonNode.Bounds.Location + Settings.ButtonRect.Location,Settings.ButtonRect.Size)
            _isButtonPressed = btnRectAbsolute.Contains(e.Location)
            If _isButtonPressed Then
                Refresh()
            End If
        End If
    End Sub
End Class

在表格中你可以写

Public Class Form1
    Private Sub Form1_Load(sender As Object,e As EventArgs) Handles MyBase.Load
        TreeView1.Nodes.Add("Text")
        TreeView1.Nodes.Add(New ButtonTreeNode("Caption","Button"))
    End Sub

    Private Sub TreeView1_NodeButtonClick(e As TreeNodeMouseClickEventArgs) _
        Handles TreeView1.NodeButtonClick

        MessageBox.Show(e.Node.Text & " clicked")
    End Sub
End Class

这会向 TreeView 添加一个普通文本节点和一个自定义按钮节点。它还处理自定义 TreeView 的 NodeButtonClick