用户在运行时调整TableLayoutPanel中的行和列的大小

时间:2013-06-18 20:39:53

标签: c# winforms

我正在开发一个WinForm项目并“尝试”创建一个TableLayoutPanel,用户可以在运行时调整它,就像SplitContainer的行为一样。我发现一些代码部分地做了这个,但它不完整。有人可以帮帮我吗?

提前致谢, -DA

这是我到目前为止的代码,它来自我在CodeProject上找到的一个帖子。我自己做的唯一不同的是创建一个继承自TableLayoutPanel的customTableLayoutPanel。

public partial class Form1 : Form
{
    bool resizing = false;
    TableLayoutRowStyleCollection rowStyles;
    TableLayoutColumnStyleCollection columnStyles;

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        rowStyles = tableLayoutPanel1.RowStyles;
        columnStyles = tableLayoutPanel1.ColumnStyles;
    }

    private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            resizing = true;
        }
    }

    private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (resizing)
        {
            columnStyles[0].SizeType = SizeType.Absolute;
            rowStyles[0].SizeType = SizeType.Absolute;
            rowStyles[0].Height = e.Y;
            columnStyles[0].Width = e.X;
        }
    }

    private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            resizing = false;
        }
    }
}

4 个答案:

答案 0 :(得分:3)

将Column SizeType和Row SizeType属性设置为Absolute和CellBorderStyle,而不是之后在代码中写入,如下所示

public partial class Form1 : Form
{
    bool resizing = false;
    TableLayoutRowStyleCollection rowStyles;
    TableLayoutColumnStyleCollection columnStyles;
    int colindex = -1;
    int rowindex = -1;
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        rowStyles = tableLayoutPanel1.RowStyles;
        columnStyles = tableLayoutPanel1.ColumnStyles;
    }
    private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            rowStyles = tableLayoutPanel1.RowStyles;
            columnStyles = tableLayoutPanel1.ColumnStyles;
            resizing = true;
        }
    }

    private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
    {
        if (!resizing)
        {
            float width = 0;
            float height = 0;
            //for rows
            for (int i = 0; i < rowStyles.Count; i++)
            {
                height += rowStyles[i].Height;
                if (e.Y > height - 3 && e.Y < height + 3)
                {
                    rowindex = i;
                    tableLayoutPanel1.Cursor = Cursors.HSplit;
                    break;
                }
                else
                {
                    rowindex = -1;
                    tableLayoutPanel1.Cursor = Cursors.Default;
                }
            }
            //for columns
            for (int i = 0; i < columnStyles.Count; i++)
            {
                width += columnStyles[i].Width;
                if (e.X > width - 3 && e.X < width + 3)
                {
                    colindex = i;
                    if (rowindex > -1)
                        tableLayoutPanel1.Cursor = Cursors.Cross;
                    else
                        tableLayoutPanel1.Cursor = Cursors.VSplit;
                    break;
                }
                else
                {
                    colindex = -1;
                    if (rowindex == -1)
                        tableLayoutPanel1.Cursor = Cursors.Default;
                }
            }
        }
        if (resizing && (colindex>-1 || rowindex > -1))
        {
            float width = e.X;
            float height = e.Y;
            if (colindex > -1)
            {
                for (int i = 0; i < colindex; i++)
                {
                    width -= columnStyles[i].Width;
                }
                columnStyles[colindex].SizeType = SizeType.Absolute;
                columnStyles[colindex].Width = width;
            }
            if (rowindex > -1)
            {
                for (int i = 0; i < rowindex; i++)
                {
                    height -= rowStyles[i].Height;
                }

                rowStyles[rowindex].SizeType = SizeType.Absolute;
                rowStyles[rowindex].Height = height;
            }
        }
    }

    private void tableLayoutPanel1_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            resizing = false;
            tableLayoutPanel1.Cursor = Cursors.Default;
        }
    }
}

答案 1 :(得分:1)

我改进了MD答案的代码 我没有收听TableLayoutPanel的MouseEvents,而是听那些控件。以下是可调整大小的的代码:

    TableLayoutPanel tlp;
    bool resizing;
    int rowindex = -1;
    int nextHeight;

    private void control_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            resizing = true;
        }
    }

    private void control_MouseMove(object sender, MouseEventArgs e)
    {
        Control c = (Control)sender;
        if (!resizing)
        {
            rowindex = -1;
            tlp.Cursor = Cursors.Default;

            if (e.Y <= 3)
            {
                rowindex = tlp.GetPositionFromControl(c).Row - 1;
                if (rowindex >= 0)
                    tlp.Cursor = Cursors.HSplit;
            }
            if (c.Height - e.Y <= 3)
            {
                rowindex = tlp.GetPositionFromControl(c).Row;
                if (rowindex < tlp.RowStyles.Count)
                    tlp.Cursor = Cursors.HSplit;
            }
        }
        if (resizing && rowindex > -1)
        {
            nextHeight = e.Y;
        }
    }

    private void control_MouseUp(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            if (nextHeight > 0)
                tlp.RowStyles[rowindex].Height = nextHeight;
            resizing = false;
        }
    }

答案 2 :(得分:0)

我的回答是使用鼠标仅调整tablelayoutpanel的列,但可以轻松更新以对行执行相同操作。当然,我宁愿使用分割板作为行,但仍然。在代码中,我可以提供4列,但将其扩展到更多或更少是很容易的。 cursurToDefault事件将添加到tablelayoutpanel内容器控件的mousemove事件中。

 private int beamMoving;
 private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
    {
        this.Cursor = Cursors.VSplit;
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            int beam0 = (int)tableLayoutPanel1.ColumnStyles[0].Width;
            int beam1 = (int)tableLayoutPanel1.ColumnStyles[0].Width + (int)tableLayoutPanel1.ColumnStyles[1].Width;
            int beam2 = (int)tableLayoutPanel1.ColumnStyles[0].Width + (int)tableLayoutPanel1.ColumnStyles[1].Width + (int)tableLayoutPanel1.ColumnStyles[2].Width;

            switch (beamMoving)
            {
                case 0:
                    {
                        if (e.X > 0)
                        {
                            tableLayoutPanel1.ColumnStyles[0].Width = e.X;
                        }
                        break;
                    }
                case 1:
                    {
                        if (e.X - beam0 > 0)
                        {
                            tableLayoutPanel1.ColumnStyles[1].Width = e.X - beam0;
                        }
                        break;
                    }
                case 2:
                    {
                        if (e.X - beam1 > 0)
                        {
                            tableLayoutPanel1.ColumnStyles[2].Width = e.X - beam1;
                        }
                        break;
                    }
            }
        }
    }
    private void cursorToDefault(object sender, MouseEventArgs e)
    {
        this.Cursor = Cursors.Default;
    }

    private void tableLayoutPanel1_MouseDown(object sender, MouseEventArgs e)
    {
        int beam0 = (int)tableLayoutPanel1.ColumnStyles[0].Width;
        int beam1 = (int)tableLayoutPanel1.ColumnStyles[0].Width + (int)tableLayoutPanel1.ColumnStyles[1].Width;
        int beam2 = (int)tableLayoutPanel1.ColumnStyles[0].Width + (int)tableLayoutPanel1.ColumnStyles[1].Width + (int)tableLayoutPanel1.ColumnStyles[2].Width;
        if (e.X + 20 > beam0 && e.X - 20 < beam1)
        {
            beamMoving = 0;
        }
        if (e.X + 20 > beam1 && e.X - 20 < beam2)
        {
            beamMoving = 1;
        }
        if (e.X + 20 > beam2 && e.X - 20 < tableLayoutPanel1.Width)
        {
            beamMoving = 2;
        }                    
    }

答案 3 :(得分:0)

根据原始代码编写模块

这使用字典和4个事件处理程序来处理多个tablelayoutpanel,以调整其行和列的大小。

其中包含一些代码,用于捕获屏幕外的内容,但不多。

阅读代码中的注释以获取更多信息

Module modResizeableTableLayoutPanel

Private otlpdic As Dictionary(Of String, Integer()) = Nothing


 ''' <summary>
 ''' Adds the needed handlers for resizing the rows and columns of multiple
 ''' tablelayoutpanel uses the tag property
 ''' also requires primary controls in the cells to have a margin of 6... this is
 ''' a hack to detect when the mouse
 ''' is no longer over a divider and not over a control in the cell
 ''' All rows and columns require absolute positioning
 ''' </summary>
 ''' <param name="otlp">tablelayoutpanel</param>
 ''' <remarks></remarks>
Public Sub InitializeResizeableTableLayOutPanel(ByRef otlp As TableLayoutPanel)
    'create has if needed
    Call CreateTableLayoutPanelHash()

    'creat hash entry for TableLayoutPanel
    Call CreateHashEntryForTableLayoutPanel(otlp)

    'sets the border style to something that helps the mouse cursor detect.
    otlp.CellBorderStyle = TableLayoutPanelCellBorderStyle.Single

    'hack to set margins on sub controls
    For Each con In otlp.Controls
        Select Case con.GetType
            Case GetType(FlowLayoutPanel)
                Dim obj As FlowLayoutPanel = DirectCast(con, FlowLayoutPanel)
                obj.Margin = New Padding(6)
            Case GetType(DataGridView)
                Dim obj As DataGridView = DirectCast(con, DataGridView)
                obj.Margin = New Padding(6)
            Case GetType(Button)
                Dim obj As Button = DirectCast(con, Button)
                obj.Margin = New Padding(6)
            Case GetType(GroupBox)
                Dim obj As GroupBox = DirectCast(con, GroupBox)
                obj.Margin = New Padding(6)
        End Select
    Next

    'add event handlers
    AddHandler otlp.MouseDown, AddressOf tlp_MouseDown
    AddHandler otlp.MouseUp, AddressOf tlp_MouseUp
    AddHandler otlp.MouseMove, AddressOf tlp_MouseMove
    AddHandler otlp.MouseLeave, AddressOf tlp_MouseLeave
End Sub

''' <summary>
''' Clear the dictionary/hashtable that keeps track of needed variables to control the resizing 
''' </summary>
''' <remarks></remarks>
Public Sub ResetResizeableTableLayOutPanelData()
    otlpdic.Clear()
    otlpdic = Nothing
    Call CreateTableLayoutPanelHash()
End Sub

Private Sub CreateTableLayoutPanelHash()
    If otlpdic Is Nothing Then
         otlpdic = New Dictionary(Of String, Integer())
    End If
End Sub

Private Sub CreateHashEntryForTableLayoutPanel(ByRef otlp As TableLayoutPanel)
    If Not otlp.Tag Is Nothing AndAlso otlpdic.ContainsKey(otlp.Tag) Then

    Else
        Dim tmpguid As Guid = Guid.NewGuid

        otlp.Tag = tmpguid.ToString

        otlpdic.Add(otlp.Tag, {0, -1, -1})
    End If
End Sub

Public Sub tlp_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs)
    If e.Button = System.Windows.Forms.MouseButtons.Left Then
        Dim otlp As TableLayoutPanel = DirectCast(sender, TableLayoutPanel)
        Call CreateHashEntryForTableLayoutPanel(otlp)
        Dim tmpdata As Integer() = otlpdic.Item(otlp.Tag)
        tmpdata(0) = -1

    End If
End Sub


Public Sub tlp_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs)
    Dim otlp As TableLayoutPanel = DirectCast(sender, TableLayoutPanel)
    Call CreateHashEntryForTableLayoutPanel(otlp)
    Dim tmpdata As Integer() = otlpdic.Item(otlp.Tag)

    'Dim rowStyles = 
        'columnStyles = TableLayoutPanel1.ColumnStyles

    If Not tmpdata(0) Then

        Dim width As Double = 0
        Dim height As Double = 0
        'for rows
        For i As Integer = 0 To otlp.RowStyles.Count - 1

            height += otlp.RowStyles(i).Height

            If (e.Y > height - 2 And e.Y < height + 2) Then

                tmpdata(1) = i
                otlp.Parent.Cursor = Cursors.HSplit
                Exit For
            Else
                tmpdata(1) = -1
                otlp.Parent.Cursor = Cursors.Default
            End If
        Next
        'for columns
        For i As Integer = 0 To otlp.ColumnStyles.Count - 1

            width += otlp.ColumnStyles(i).Width
            If e.X > width - 2 And e.X < width + 2 Then

                tmpdata(2) = i
                If (tmpdata(1) > -1) Then
                    otlp.Parent.Cursor = Cursors.Cross
                Else
                    otlp.Parent.Cursor = Cursors.VSplit
                    Exit For
                End If
            Else

                tmpdata(2) = -1
                If (tmpdata(1) = -1) Then
                    otlp.Parent.Cursor = Cursors.Default
                End If
            End If
        Next
    End If
    If (tmpdata(0) And (tmpdata(2) > -1 Or tmpdata(1) > -1)) Then

        Dim Width As Double = e.X
        Dim Height As Double = e.Y

        If e.X > otlp.Width - 100 Then
            Exit Sub
        End If

        If e.Y > otlp.Height - 100 Then
            Exit Sub
        End If



        If (tmpdata(2) > -1) Then
            For i As Integer = 0 To tmpdata(2) - 1

                Width -= otlp.ColumnStyles(i).Width
            Next
            otlp.ColumnStyles(tmpdata(2)).SizeType = SizeType.Absolute


            If Width < 10 Then
                Width = 10
            End If

            If Width > otlp.Width - 100 Then
                Width = otlp.Width - 100
            End If



            otlp.ColumnStyles(tmpdata(2)).Width = Width
        End If
        If (tmpdata(1) > -1) Then

            For i As Integer = 0 To tmpdata(1) - 1

                Height -= otlp.RowStyles(i).Height
            Next
            otlp.RowStyles(tmpdata(1)).SizeType = SizeType.Absolute

            If Height < 10 Then
                Height = 10
            End If

            If Height > otlp.Height - 100 Then
                Height = otlp.Height - 100
            End If


            otlp.RowStyles(tmpdata(1)).Height = Height
        End If
    End If
End Sub


Public Sub tlp_MouseLeave(sender As Object, e As System.EventArgs)
    Dim otlp As TableLayoutPanel = DirectCast(sender, TableLayoutPanel)
    otlp.Parent.Cursor = Cursors.Default
End Sub

Public Sub tlp_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs)
    If e.Button = System.Windows.Forms.MouseButtons.Left Then
        Dim otlp As TableLayoutPanel = DirectCast(sender, TableLayoutPanel)
        Dim tmpdata As Integer() = otlpdic.Item(otlp.Tag)
        tmpdata(0) = 0
        otlp.Parent.Cursor = Cursors.Default
    End If
End Sub
End Module