TableLayoutPanel sizing

GeoffM picture GeoffM · Sep 1, 2011 · Viewed 36.7k times · Source

I may not be using the right control for what I want. I'm filling a table with controls and I want each column to automatically size to the controls contained within it. For example, a column of textboxes will be wider than a column of checkboxes. I don't want to fiddle with measuring if I can help it, due to the complexities of different OS, different DPI, different fonts, etc. The table can expand horizontally to fit the controls, with a scrollbar. How is this possible with a TableLayoutPanel - or some other control?

Thanks.

Edited to add code:

    private void UpdateLocations()
    {
        tableLayoutPanel1.RowCount = CurrentSchedule.location.Length + 1;
        tableLayoutPanel1.ColumnCount = 7;
        int row = 1;
        int timeWidth = TextRenderer.MeasureText("00:00:00x", tableLayoutPanel1.Font).Width;

        Label lab = new Label();
        lab.Text = "Location";
        tableLayoutPanel1.Controls.Add(lab, 0, 0);

        lab = new Label();
        lab.Text = "Arrive";
        tableLayoutPanel1.Controls.Add(lab, 1, 0);

        lab = new Label();
        lab.Text = "Depart";
        tableLayoutPanel1.Controls.Add(lab, 2, 0);

        lab = new Label();
        lab.Text = "Pass?";
        tableLayoutPanel1.Controls.Add(lab, 3, 0);

        lab = new Label();
        lab.Text = "Path";
        tableLayoutPanel1.Controls.Add(lab, 4, 0);

        lab = new Label();
        lab.Text = "Plat";
        tableLayoutPanel1.Controls.Add(lab, 5, 0);

        lab = new Label();
        lab.Text = "Line";
        tableLayoutPanel1.Controls.Add(lab, 6, 0);

        foreach (location loc in CurrentSchedule.location)
        {
            TextBox tb = new TextBox();
            tb.Text = loc.locationID;
            tableLayoutPanel1.Controls.Add(tb, 0, row);

            tb = new TextBox();
            tb.Text = loc.arrivalTime;
            tb.Width = timeWidth;
            tableLayoutPanel1.Controls.Add(tb, 1, row);

            tb = new TextBox();
            tb.Text = loc.departureTime;
            tb.Width = timeWidth;
            tableLayoutPanel1.Controls.Add(tb, 2, row);

            CheckBox cb = new CheckBox();
            cb.Checked = loc.passingTime;
            tableLayoutPanel1.Controls.Add(cb, 3, row);

            tb = new TextBox();
            tb.Text = loc.pathCode;
            tableLayoutPanel1.Controls.Add(tb, 4, row);

            tb = new TextBox();
            tb.Text = loc.platformCode;
            tableLayoutPanel1.Controls.Add(tb, 5, row);

            tb = new TextBox();
            tb.Text = loc.lineCode;
            tableLayoutPanel1.Controls.Add(tb, 6, row);

            row++;
        }
        /*for (int idx = 0; idx < tableLayoutPanel1.RowCount; idx++)
        {
            tableLayoutPanel1.RowStyles[idx].SizeType = SizeType.AutoSize;
        }
        for (int idx = 0; idx < tableLayoutPanel1.ColumnCount; idx++)
        {
            tableLayoutPanel1.ColumnStyles[idx].SizeType = SizeType.AutoSize;
        }*/
    }

(Yes it needs heavy refactoring - I'm just trying to get it to work first)

The commented out bits cause out of bounds exceptions, even though logically (to me) it shouldn't. The range appears limited to whatever I set at design time, not at runtime.

Answer

Justin Doyle picture Justin Doyle · Sep 2, 2011

Sorry, but what's wrong with having the columns set to Autosize? That's what TableLayoutPanel does, size columns to the fit the controls within it. Expanding the table and having a scrollbar would require you to set the tables Autosize property to true, then sit the TableLayoutPanel within another panel that has scrollbars enabled. But the column sizing should work out of the box if unless I'm misunderstanding your requirements.

Just to make sure, you are going to the columns property and setting each column's SizeType to AutoSize right? Not just the AutoSize property of the table itself?

enter image description here

is this what you want?

-Post code:

Thanks for the code. I'd suggest that you use designer to do a lot of this. At least to set up the columns, set them to autosize, and add the heading labels.

You also might want to check out the Datagrid control and bind that to your location list.

To get this method working though:

1) the reason your columns look the same size is because the heading labels you're using aren't autosizing. They're all x pixels wide and that's stretching the columns. Do this:

Label lab = new Label();
lab.AutoSize = true;
lab.Text = "Location";
tableLayoutPanel1.Controls.Add(lab, 0, 0);

You'll also need to set the AutoSize property to true on the CheckBox control and any other labels you add as content.

2) Setting the RowCount and ColumnCount won't affect the RowStyles or ColumnStyles collection. You've got 7 Columns but only 2 ColumnStyles. Try:

tableLayoutPanel1.ColumnStyles.Clear();
for (int i = 0; i < tableLayoutPanel1.ColumnCount; i++)
{
   tableLayoutPanel1.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
}

tableLayoutPanel1.RowStyles.Clear();
for (int i = 0; i < tableLayoutPanel1.RowCount; i++)
{
   tableLayoutPanel1.RowStyles.Add(new RowStyle(SizeType.AutoSize));
}

Only other thing to look out for is that some controls will be misaligned in the rows (labels appear too high for example). To fix that set the Margin property, normally to 3,6,3,0 to align them with textboxes and checkboxes etc.