(VB.net)自定义TableLayoutPanel使它能够在运行时用鼠标改变行高和列宽。

喜欢看C#的童鞋,这里有个工具,你们可以自己转换:http://converter.telerik.com/

想达到这个效果,首先新建一个新的项目。在项目名字上面右击,新增一个类,类名为:TableLayoutPanelEx.vb。 然后只要复制下面的代码到类中即可。

Public Class TableLayoutPanelEx
    Inherits TableLayoutPanel

    Private Const WM_NCHITTEST As Integer = &H84
    Private Const WM_MOUSEMOVE As Integer = &H200
    Private Const WM_LBUTTONDOWN As Integer = &H201
    Private Const WM_LBUTTONUP As Integer = &H202
    Private Const MK_LBUTTON As Integer = &H1

    Private VBorders As New List(Of Integer)
    Private HBorders As New List(Of Integer)
    Private selColumn As Integer = -1
    Private selRow As Integer = -1

    Public Sub New()
        Me.DoubleBuffered = True
        Me.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single
    End Sub

    Protected Overrides Sub OnHandleCreated(ByVal e As System.EventArgs)
        MyBase.OnHandleCreated(e)
        If Not Me.DesignMode Then ResetSizeAndSizeTypes()
    End Sub

    Public Shadows Property ColumnCount() As Integer
        Get
            Return MyBase.ColumnCount
        End Get
        Set(ByVal value As Integer)
            MyBase.ColumnCount = value
            If Me.Created And Not Me.DesignMode Then ResetSizeAndSizeTypes()
        End Set
    End Property

    Public Shadows Property RowCount() As Integer
        Get
            Return MyBase.RowCount
        End Get
        Set(ByVal value As Integer)
            MyBase.RowCount = value
            If Me.Created And Not Me.DesignMode Then ResetSizeAndSizeTypes()
        End Set
    End Property

    Public Sub ResetSizeAndSizeTypes()
        Dim cW As Single = CSng((Me.ClientSize.Width \ Me.GetColumnWidths.Length) - 1)
        For c As Integer = 0 To Me.GetColumnWidths.Length - 1
            Me.ColumnStyles(c).SizeType = SizeType.Absolute
            Me.ColumnStyles(c).Width = cW
        Next

        Dim cH As Single = CSng((Me.ClientSize.Height \ Me.GetRowHeights.Length) - 1)
        For r As Integer = 0 To Me.GetRowHeights.Length - 1
            Me.RowStyles(r).SizeType = SizeType.Absolute
            Me.RowStyles(r).Height = cH
        Next
    End Sub

    Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
        MyBase.WndProc(m)
        If Me.Created And Not Me.Disposing Then
            If m.Msg = WM_NCHITTEST Then
                Dim loc As Point = Me.PointToClient(MousePosition)
                VBorders.Clear()
                HBorders.Clear()
                If Me.ColumnCount > 1 Then
                    For w As Integer = 0 To Me.GetColumnWidths.Length - 2
                        If w = 0 Then
                            VBorders.Add(Me.GetColumnWidths(w))
                        Else
                            VBorders.Add(VBorders(VBorders.Count - 1) + Me.GetColumnWidths(w))
                        End If
                    Next
                End If
                If Me.RowCount > 1 Then
                    For h As Integer = 0 To Me.GetRowHeights.Length - 2
                        If h = 0 Then
                            HBorders.Add(Me.GetRowHeights(h))
                        Else
                            HBorders.Add(HBorders(HBorders.Count - 1) + Me.GetRowHeights(h))
                        End If
                    Next
                End If

                Dim onV As Boolean = (VBorders.Contains(loc.X) Or VBorders.Contains(loc.X - 1) Or VBorders.Contains(loc.X + 1))
                Dim onH As Boolean = (HBorders.Contains(loc.Y) Or HBorders.Contains(loc.Y - 1) Or HBorders.Contains(loc.Y + 1))
                If onV And onH Then
                    Me.Cursor = Cursors.SizeAll
                ElseIf onV Then
                    Me.Cursor = Cursors.VSplit
                ElseIf onH Then
                    Me.Cursor = Cursors.HSplit
                Else
                    Me.Cursor = Cursors.Default
                End If

            ElseIf m.Msg = WM_LBUTTONDOWN And Me.Cursor <> Cursors.Default Then
                Dim loc As Point = Me.PointToClient(MousePosition)
                selColumn = -1
                selRow = -1
                For c As Integer = 0 To VBorders.Count - 1
                    If VBorders(c) >= loc.X - 1 And VBorders(c) <= loc.X + 1 Then
                        selColumn = c
                        Exit For
                    End If
                Next
                For r As Integer = 0 To HBorders.Count - 1
                    If HBorders(r) >= loc.Y - 1 And HBorders(r) <= loc.Y + 1 Then
                        selRow = r
                        Exit For
                    End If
                Next

            ElseIf m.Msg = WM_MOUSEMOVE And m.WParam.ToInt32 = MK_LBUTTON Then
                Dim loc As Point = Me.PointToClient(MousePosition)
                If Me.Cursor <> Cursors.Default Then

                    If selRow > -1 And loc.Y >= 1 And loc.Y <= Me.ClientSize.Height - 2 Then
                        Me.RowStyles(selRow).SizeType = SizeType.Absolute

                        Dim ref As Single = loc.Y - Me.RowStyles(selRow).Height
                        If selRow > 0 Then ref -= HBorders(selRow - 1)

                        If Me.RowStyles(selRow).Height + ref > 0 Then

                            If Me.RowCount > selRow + 1 Then
                                If Me.RowStyles(selRow + 1).Height - ref < 1 Then Exit Sub
                                Me.RowStyles(selRow + 1).Height -= ref
                            End If

                            Me.RowStyles(selRow).Height += ref
                        End If
                    End If

                    If selColumn > -1 And loc.X >= 1 And loc.X <= Me.ClientSize.Width - 2 Then
                        Me.ColumnStyles(selColumn).SizeType = SizeType.Absolute

                        Dim ref As Single = loc.X - Me.ColumnStyles(selColumn).Width
                        If selColumn > 0 Then ref -= VBorders(selColumn - 1)

                        If Me.ColumnStyles(selColumn).Width + ref > 0 Then

                            If Me.ColumnCount > selColumn + 1 Then
                                If Me.ColumnStyles(selColumn + 1).Width - ref < 1 Then Exit Sub
                                Me.ColumnStyles(selColumn + 1).Width -= ref
                            End If

                            Me.ColumnStyles(selColumn).Width += ref
                        End If

                    End If

                End If

            ElseIf m.Msg = WM_LBUTTONUP Then
                selColumn = -1
                selRow = -1
            End If
        End If
    End Sub
End Class

  然后你需要build一下你的工程。build之后在工具箱中会自动生成TableLayoutPanelEx控件。你需要把他拉到form中即可。然后有个重要的地方需要注意下:你需要设置RowCountColumnCount属性,达到你想达到的最大值,我们假设为10行10列吧,就设置RowCount等于10,ColumnCount等于10,这些都是在窗口设计模式中做到的。
  接下来,我们再加两个NumericUpDown控件到Form中,命名为 (NUD_Rows) 和 (NUD_Columns)

  最后把下面的代码放到Form中即可。

Public Class Form1

    Public Sub New()
        InitializeComponent()

        'Set the minimum of the 2 NumericUpDown controls for the rows and columns to 1
        'Set the maximum of the 2 NumericUpDown controls to the number of rows and columns you have set in the [Design] tab properties
        NUD_Rows.Minimum = 1
        NUD_Rows.Maximum = TableLayoutPanelEx1.RowCount
        NUD_Columns.Minimum = 1
        NUD_Columns.Maximum = TableLayoutPanelEx1.ColumnCount

        'Set to the rows and columns counts back to what you want for the default
        TableLayoutPanelEx1.ColumnCount = 4
        TableLayoutPanelEx1.RowCount = 4

        'Set the 2 NumericUpDown control values to the current count of rows and columns
        NUD_Rows.Value = TableLayoutPanelEx1.RowCount
        NUD_Columns.Value = TableLayoutPanelEx1.ColumnCount
    End Sub

    Private Sub NUD_Rows_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NUD_Rows.ValueChanged
        If Me.Created Then TableLayoutPanelEx1.RowCount = CInt(NUD_Rows.Value)
    End Sub

    Private Sub NUD_Columns_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NUD_Columns.ValueChanged
        If Me.Created Then TableLayoutPanelEx1.ColumnCount = CInt(NUD_Columns.Value)
    End Sub
End Class

 你可以运行和调试了。Good lucy baby! 

理想的效果应该是你可以用鼠标改变行高和列宽了。可以通过 NumericUpDown控件改变行数和列数。

这边是我的效果图:

posted @ 2015-03-30 17:27  Youjun  阅读(2164)  评论(1编辑  收藏  举报