How do I determine the cell being clicked on in a TableLayoutPanel?
Asked Answered
C

5

9

I have a TableLayoutPanel and I want to add a control to the cell that I click on.

The problem is that I can't determine the cell that I click on at run time.

How do I determine the cell being clicked on?

Cosine answered 16/3, 2013 at 12:53 Comment(0)
O
16

You can use GetColumnWidths and GetRowHeights methods to calculate the cell row and column index:

Point? GetRowColIndex(TableLayoutPanel tlp, Point point)
{
    if (point.X > tlp.Width || point.Y > tlp.Height)
        return null;

    int w = tlp.Width;
    int h = tlp.Height;
    int[] widths = tlp.GetColumnWidths();

    int i;
    for (i = widths.Length - 1; i >= 0 && point.X < w; i--)
        w -= widths[i];
    int col = i + 1;

    int[] heights = tlp.GetRowHeights();
    for (i = heights.Length - 1; i >= 0 && point.Y < h; i--)
        h -= heights[i];

    int row = i + 1;

    return new Point(col, row);
}

Usage:

private void tableLayoutPanel1_Click(object sender, EventArgs e)
{
    var cellPos = GetRowColIndex(
        tableLayoutPanel1,
        tableLayoutPanel1.PointToClient(Cursor.Position));
}

But notice that the click event only is raised if the cell does not already contain a control.

Oleograph answered 16/3, 2013 at 13:41 Comment(4)
I cant find GetColumnWidths and GetRowHeightsCosine
@AymanSharaf Don't worry. They are not visible in the Visual Studio Intellisence. They have [Browsable(false)] attribute, but they exist, and if you use my code, you'll see that they will work.Oleograph
This looks like the same answer posted on pcreview.co.uk from Feb 2006.Walleye
Thanks! I would have called that GetColRow() however, since first element X is the column ;-)Gaudet
P
4

This worked for me:

public TableLayoutPanel tableLayoutPanel { get; set; }

private void Form_Load(object sender, EventArgs e)
{
    foreach (Panel space in this.tableLayoutPanel.Controls)
    {
        space.MouseClick += new MouseEventHandler(clickOnSpace);
    }
}

public void clickOnSpace(object sender, MouseEventArgs e)
{

    MessageBox.Show("Cell chosen: (" + 
                     tableLayoutPanel.GetRow((Panel)sender) + ", " + 
                     tableLayoutPanel.GetColumn((Panel)sender) + ")");
}

Note that my tableLayoutPanel is declared globally so that I can just use it without having to pass it to each function. Also, both the tableLayoutPanel and each Panel within it are created completely programatically elsewhere (my form [design] is completely blank).

Psychopharmacology answered 8/8, 2016 at 20:35 Comment(0)
C
2

My answer is based on @Mohammad Dehghan's answer above but has a couple of advantages:

  • It now takes into account vertical scrolling
  • The columns are in the correct order (starts at i=0 instead of i=length), meaning columns of different widths or heights are processed in the correct order

Here is the updated version of the code:

public Point? GetIndex(TableLayoutPanel tlp, Point point)
{
    // Method adapted from: stackoverflow.com/a/15449969
    if (point.X > tlp.Width || point.Y > tlp.Height)
        return null;

    int w = 0, h = 0;
    int[] widths = tlp.GetColumnWidths(), heights = tlp.GetRowHeights();

    int i;
    for (i = 0; i < widths.Length && point.X > w; i++)
    {
        w += widths[i];
    }
    int col = i - 1;

    for (i = 0; i < heights.Length && point.Y + tlp.VerticalScroll.Value > h; i++)
    {
        h += heights[i];
    }
    int row = i - 1;

    return new Point(col, row);
}
Crackup answered 30/1, 2017 at 12:3 Comment(0)
L
0

Nick's answer was the best solution, except that it can be made generic for TableLayoutPanels that contain different kinds of controls in the cells. Just change the explicit "Panel" type to "Control":

public TableLayoutPanel tableLayoutPanel { get; set; }

private void Form_Load(object sender, EventArgs e)
{
    foreach (Control c in this.tableLayoutPanel.Controls)
    {
        c.MouseClick += new MouseEventHandler(ClickOnTableLayoutPanel);
    }
}

public void ClickOnTableLayoutPanel(object sender, MouseEventArgs e)
{

    MessageBox.Show("Cell chosen: (" + 
                     tableLayoutPanel.GetRow((Control)sender) + ", " + 
                     tableLayoutPanel.GetColumn((Control)sender) + ")");
}

This works great and doesn't require doing coordinate math to find which cell was clicked.

Langevin answered 6/7, 2019 at 23:35 Comment(0)
W
0
PictureEdit ped = new PictureEdit();
 ped.MouseClick += new MouseEventHandler((o, a) => your code);
Wanting answered 3/9, 2024 at 7:13 Comment(1)
Thank you for your interest in contributing to the Stack Overflow community. This question already has a few answers—including one that has been validated by the community. Are you certain your approach hasn’t been given previously? If so, it would be useful to explain how your approach is different, under what circumstances your approach might be preferred, and/or why you think the previous answers aren’t sufficient. Can you kindly edit your answer to offer an explanation?Gnash

© 2022 - 2025 — McMap. All rights reserved.