【问题标题】:How to make TableLayoutPanel with resizable cells like using Splitter如何使用可调整大小的单元格制作 TableLayoutPanel,例如使用 Splitter
【发布时间】:2015-09-13 04:29:27
【问题描述】:

得到 1 列 N 行的 TableLayoutPanel 需要通过单元格之间的拆分器组件来调整单元格的大小。 不使用 SplitContainer。

没有 TableLayoutPanel 可能还有其他想法吗?

【问题讨论】:

  • 您可能最好使用单列 DataGridView 并将 AllowUserToResizeRows 设置为 true 并翻转行和列标题。
  • 只有 1 列,flowlayoutpanel 可能更方便(flowdirection topdown 和 wrapcontents=false),拆分器只需要调整控件的大小,flowlayout 就会随之而来。碰巧的是,已经有一个使用拆分器实现流程布局的项目:codeproject.com/Articles/43158/…。没试过,但它可能是你需要的。

标签: c# winforms tablelayoutpanel splitter


【解决方案1】:

这真的取决于你想用它做什么:DataGridView 带来了交互性,但它的单元格既不是控件也不是容器..

你可以试试这个TableLayoutPanel子类是否符合你的要求:

public partial class SplitTablePanel : TableLayoutPanel
{
    public int SplitterSize { get; set; }

    int sizingRow = -1;
    int currentRow = -1;
    Point mdown = Point.Empty;
    int oldHeight = -1;
    bool isNormal = false;
    List<RectangleF> TlpRows = new List<RectangleF>();
    int[] rowHeights = new int[0];

    public SplitTablePanel()
    {
        InitializeComponent();
        this.MouseDown += SplitTablePanel_MouseDown;
        this.MouseMove += SplitTablePanel_MouseMove;
        this.MouseUp += SplitTablePanel_MouseUp;
        this.MouseLeave += SplitTablePanel_MouseLeave;
        SplitterSize = 6;
    }

    void SplitTablePanel_MouseLeave(object sender, EventArgs e)
    {
        Cursor = Cursors.Default;
    }


    void SplitTablePanel_MouseUp(object sender, MouseEventArgs e)
    {
        getRowRectangles(SplitterSize);
    }

    void SplitTablePanel_MouseMove(object sender, MouseEventArgs e)
    {
        if (!isNormal) nomalizeRowStyles();
        if (TlpRows.Count <= 0) getRowRectangles(SplitterSize);
        if (rowHeights.Length <= 0) rowHeights = GetRowHeights();

        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            if (sizingRow < 0) return;
            int newHeight = oldHeight + e.Y - mdown.Y;
            sizeRow(sizingRow, newHeight);
        }
        else
        {
            currentRow = -1;
            for (int i = 0; i < TlpRows.Count; i++)
                if (TlpRows[i].Contains(e.Location)) { currentRow = i; break;}
            Cursor = currentRow >= 0 ? Cursors.SizeNS : Cursors.Default;
        }
    }

    void SplitTablePanel_MouseDown(object sender, MouseEventArgs e)
    {
        mdown = Point.Empty;
        sizingRow = -1;
        if (currentRow < 0) return;
        sizingRow = currentRow;
        oldHeight = rowHeights[sizingRow];
        mdown = e.Location;
    }


    void getRowRectangles(float size)
    {   // get a list of mouse sensitive rectangles
        float sz = size / 2f;
        float y = 0f;
        int w = ClientSize.Width;
        int[] rw = GetRowHeights();

        TlpRows.Clear();
        for (int i = 0; i < rw.Length - 1; i++)
        {
            y += rw[i];
            TlpRows.Add(new RectangleF(0, y - sz, w, size));
        }

    }

    void sizeRow(int row, int newHeight)
    {   // change the height of one row
        if (newHeight == 0) return;
        if (sizingRow < 0) return;
        SuspendLayout();
        rowHeights = GetRowHeights();
        if (sizingRow >= rowHeights.Length) return;

        if (newHeight > 0) 
            RowStyles[sizingRow] = new RowStyle(SizeType.Absolute, newHeight);
        ResumeLayout();
        rowHeights = GetRowHeights();
        getRowRectangles(SplitterSize);
    }

    void nomalizeRowStyles()
    {   // set all rows to absolute and the last one to percent=100!
        if (rowHeights.Length <= 0) return;
        rowHeights = GetRowHeights();
        RowStyles.Clear();
        for (int i = 0; i < RowCount - 1; i++)
        {
            RowStyle cs = new RowStyle(SizeType.Absolute, rowHeights[i]);
            RowStyles.Add(cs);
        }
        RowStyles.Add ( new RowStyle(SizeType.Percent, 100) );
        isNormal = true;
    }
}
}

【讨论】:

    【解决方案2】:

    除了TaW 's great answer,这里还有一个更进一步的方法,它允许调整行和列的大小,并关闭一个在调整控件大小时出现的小错误(-> 在 TaW 的代码中,分割矩形也没有调整大小)。

    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Windows.Forms;
    
    namespace SomeNameSpace.Controls
    {   
        public partial class SplitTableLayoutPanel : TableLayoutPanel
        {
            public int SplitterSize { get; set; }
    
            int sizingRow = -1;
            int currentRow = -1;
            Point mdown = Point.Empty;
            int oldHeight = -1;
            bool isNormalRow = false;
            List<RectangleF> tlpRows = new List<RectangleF>();
            int[] rowHeights = new int[0];
    
            int sizingCol = -1;
            int currentCol = -1;
            int oldWidth = -1;
            bool isNormalCol = false;
            List<RectangleF> tlpCols = new List<RectangleF>();
            int[] colWidths = new int[0];
    
            public SplitTableLayoutPanel()
            {
                InitializeComponent();
                this.MouseDown += SplitTablePanel_MouseDown;
                this.MouseMove += SplitTablePanel_MouseMove;
                this.MouseUp += SplitTablePanel_MouseUp;
                this.MouseLeave += SplitTablePanel_MouseLeave;
                this.Resize += SplitTablePanel_Resize;
                SplitterSize = 6;
            }
    
            void SplitTablePanel_Resize(object sender, EventArgs e)
            {
                getRowRectangles(SplitterSize);
                getColRectangles(SplitterSize);
            }
            void SplitTablePanel_MouseLeave(object sender, EventArgs e)
            {
                Cursor = Cursors.Default;
            }
    
    
            void SplitTablePanel_MouseUp(object sender, MouseEventArgs e)
            {
                getRowRectangles(SplitterSize);
                getColRectangles(SplitterSize);
            }
    
            void SplitTablePanel_MouseMove(object sender, MouseEventArgs e)
            {
                bool r = rowMove(sender, e);
                bool c = colMove(sender, e);    
    
                if (r && !c)
                    Cursor = Cursors.SizeNS;
                else if (!r && c)
                    Cursor = Cursors.SizeWE;
                else if (r && c)
                    Cursor = Cursors.SizeAll;
                else
                    Cursor = Cursors.Default;
            }
    
            bool rowMove(object sender, MouseEventArgs e)
            {
                bool isMove = false;
                if (!isNormalRow) nomalizeRowStyles();
                if (tlpRows.Count <= 0) getRowRectangles(SplitterSize);
                if (rowHeights.Length <= 0) rowHeights = GetRowHeights();
    
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    if (sizingRow < 0) return false;
                    int newHeight = oldHeight + e.Y - mdown.Y;
                    sizeRow(sizingRow, newHeight);
                    isMove = true;
                }
                else
                {
                    currentRow = -1;
                    for (int i = 0; i < tlpRows.Count; i++)
                    if (tlpRows[i].Contains(e.Location)) 
                    { 
                        currentRow = i;
                        isMove = true;
                        break;
                    }
                }
                return isMove;
            }
    
            bool colMove(object sender, MouseEventArgs e)
            {
                bool isMove = false;
                if (!isNormalCol) nomalizeColStyles();
                if (tlpCols.Count <= 0) getColRectangles(SplitterSize);
                if (colWidths.Length <= 0) colWidths = GetColumnWidths();
    
                if (e.Button == System.Windows.Forms.MouseButtons.Left)
                {
                    if (sizingCol < 0) return false;
                    int newWidth = oldWidth + e.X - mdown.X;
                    sizeCol(sizingCol, newWidth);
                    isMove = true;
                }
                else
                {
                    currentCol = -1;
                    for (int i = 0; i < tlpCols.Count; i++)
                    if (tlpCols[i].Contains(e.Location)) 
                    {
                        currentCol = i; 
                        isMove = true;
                        break;
                    }
                }
                return isMove;
            }
    
            void SplitTablePanel_MouseDown(object sender, MouseEventArgs e)
            {
                mdown = Point.Empty;
                rowDown();   
                colDown();
                mdown = e.Location;
            }
    
            void rowDown()
            {
                sizingRow = -1;
                if (currentRow < 0) return;
                sizingRow = currentRow;
                oldHeight = rowHeights[sizingRow];
            }
    
            void colDown()
            {
                sizingCol = -1;
                if (currentCol < 0) return;
                sizingCol = currentCol;
                oldWidth = colWidths[sizingCol];
            }
    
    
            void getRowRectangles(float size)
            {   // get a list of mouse sensitive rectangles
                float sz = size / 2f;
                float y = 0f;
                int w = ClientSize.Width;
                int[] rw = GetRowHeights();
    
                tlpRows.Clear();
                for (int i = 0; i < rw.Length - 1; i++)
                {
                    y += rw[i];
                    tlpRows.Add(new RectangleF(0, y - sz, w, size));
                }
    
            }
    
            void getColRectangles(float size)
            {   // get a list of mouse sensitive rectangles
                float sz = size / 2f;
                float x = 0f;
                int h = ClientSize.Height;
                int[] rw = GetColumnWidths();
    
                tlpCols.Clear();
                for (int i = 0; i < rw.Length - 1; i++)
                {
                    x += rw[i];
                    tlpCols.Add(new RectangleF(x - sz, 0, size, h));
                }
    
            }
    
            void sizeRow(int row, int newHeight)
            {   // change the height of one row
                if (newHeight == 0) return;
                if (sizingRow < 0) return;
                SuspendLayout();
                rowHeights = GetRowHeights();
                if (sizingRow >= rowHeights.Length) return;
    
                if (newHeight > 0) 
                    RowStyles[sizingRow] = new RowStyle(SizeType.Absolute, newHeight);
                ResumeLayout();
                rowHeights = GetRowHeights();
                getRowRectangles(SplitterSize);
            }
    
            void sizeCol(int col, int newWidth)
            {   // change the height of one row
                if (newWidth == 0) return;
                if (sizingCol < 0) return;
                SuspendLayout();
                colWidths = GetColumnWidths();
                if (sizingCol >= colWidths.Length) return;
    
                if (newWidth > 0) 
                    ColumnStyles[sizingCol] = new ColumnStyle(SizeType.Absolute, newWidth);
                ResumeLayout();
                colWidths = GetColumnWidths();
                getColRectangles(SplitterSize);
            }
    
            void nomalizeRowStyles()
            {   // set all rows to absolute and the last one to percent=100!
                if (rowHeights.Length <= 0) return;
                rowHeights = GetRowHeights();
                RowStyles.Clear();
                for (int i = 0; i < RowCount - 1; i++)
                {
                    RowStyle cs = new RowStyle(SizeType.Absolute, rowHeights[i]);
                    RowStyles.Add(cs);
                }
                RowStyles.Add ( new RowStyle(SizeType.Percent, 100) );
                isNormalRow = true;
            }
    
            void nomalizeColStyles()
            {   // set all rows to absolute and the last one to percent=100!
                if (colWidths.Length <= 0) return;
                colWidths = GetColumnWidths();
                ColumnStyles.Clear();
                for (int i = 0; i < ColumnCount - 1; i++)
                {
                    ColumnStyle cs = new ColumnStyle(SizeType.Absolute, colWidths[i]);
                    ColumnStyles.Add(cs);
                }
                ColumnStyles.Add ( new ColumnStyle(SizeType.Percent, 100) );
                isNormalCol = true;
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      我无法对 steve-e 的上一篇文章发表评论,因为我是新用户,但我在试用他的控件版本时确实发现了一个错误。如果您使用鼠标滚轮,所有分离器都将停止工作。如果您滚动回顶部,它们又可以了。这是因为每当您使用鼠标滚轮向下滚动面板时,tlpRows 中每条记录的 RectangeF Y 参数都会计算错误,因此需要根据滚动移动的距离进行偏移。 为此,我为 MouseWheel 和 Scroll 事件添加了一个事件,该事件将调用 getRowRectangles 并传入一个新参数来保存偏移量 (AutoScrollPosition.Y)。 在getRowRectangles 方法中,我在创建tlpRows 列表时将偏移量添加到Y 参数中。

      tlpRows.Add(new RectangleF(0, y - sz + offset, w, size));
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-09-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多