Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make TableLayoutPanel with resizable cells like using Splitter

Got TableLayoutPanel with 1 column and N rows needed to cells be resizable with somthing like Splitter component between cells. without using SplitContainer.

May be any other idea without TableLayoutPanel?

like image 918
E.Monogarov Avatar asked Jun 26 '15 09:06

E.Monogarov


2 Answers

It really depends on what you want to do with it: A DataGridView brings with it the interactivity, but its cells are neither controls nor containers..

You can try if this TableLayoutPanel subclass does what you want:

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;
    }
}
}
like image 187
TaW Avatar answered Nov 15 '22 02:11

TaW


In addition to TaW 's great answer, here is further approach that allows to resize rows and columns as well and closes a little bug that appears if the control is resized (-> in TaW's code the splitter rectangles are not resized too).

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;
        }
    }
}
like image 34
stev-e Avatar answered Nov 15 '22 04:11

stev-e