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

byqmnocz  于 2023-02-24  发布在  其他
关注(0)|答案(5)|浏览(291)

我在一个WinForm项目上工作,并且“尝试”创建一个TableLayoutPanel,用户可以在运行时像SplitContainer一样调整它的大小。我发现了一些代码,部分地做到了这一点,但是它是不完整的。有人能帮我吗?
先谢了-检察官
到目前为止,这是我在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;
        }
    }
}
jk9hmnmh

jk9hmnmh1#

将Column SizeType和Row SizeType属性设置为Absolute,并将CellBorderStyle设置为您想要的任何样式,而不是在代码编写过程中设置为None,如下所示

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;
        }
    }
}
eqoofvh9

eqoofvh92#

我改进了MD的答案代码。
我不监听TableLayoutPanel的MouseEvents,而是监听控件的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;
        }
    }
frebpwbc

frebpwbc3#

我的答案是使用鼠标只调整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;
        }                    
    }
piztneat

piztneat4#

根据原始代码编写模块
它使用一个字典和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
9w11ddsr

9w11ddsr5#

我稍微修改了一下,原始代码没有与边框对齐。2我还希望当应用程序加载时,列的大小默认为自动调整。3我使用了tableLayoutPanel1.GetRowHeights()和表格布局面板1.GetColumn宽度(),我从https://stackoverflow.com/a/51993386/13729116中找到了它,Jazimov解释说,这是对Intellisense隐藏的,因为它不应该与跨列的控件一起工作。我测试了这个,它确实有一个奇怪的地方,你可以在控件周围的填充区域移动被跨接控件隐藏的列。我相信如果你愿意,你可以解决这个问题。

private void tableLayoutPanel1_MouseMove(object sender, MouseEventArgs e)
    {            
        if (!resizing)
        {
            float width = 0;
            float height = 0;
            int[] rowHeights = tableLayoutPanel1.GetRowHeights();
            int[] colWidths = tableLayoutPanel1.GetColumnWidths();
            //for rows
            for (int i = 0; i < rowHeights.Count(); i++)
            {
                height += rowHeights[i];
                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 < colWidths.Count(); i++)
            {
                width += colWidths[i];
                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;
            int[] rowHeights = tableLayoutPanel1.GetRowHeights();
            int[] colWidths = tableLayoutPanel1.GetColumnWidths();
            if (colindex > -1)
            {
                for (int i = 0; i < colindex; i++)
                {
                    width -= colWidths[i];
                }
                columnStyles[colindex].SizeType = SizeType.Absolute;
                columnStyles[colindex].Width = width;
            }
            if (rowindex > -1)
            {
                for (int i = 0; i < rowindex; i++)
                {
                    height -= rowHeights[i];
                }

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

相关问题