(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中即可。然后有个重要的地方需要注意下:你需要设置RowCount 和 ColumnCount属性,达到你想达到的最大值,我们假设为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控件改变行数和列数。
这边是我的效果图: