Henrique Miranda
Henrique Miranda

Reputation: 1108

How to horizontally center multiple objects inside a given container?

I have spent all day trying to solve this with no satisfying results.

I have to center some labels inside their container (a panel). If there were just one label it would be a breeze, but life ain't easy and I have to write a method to center multiple objects and overcome two problems:

  1. It could be any number of labels between 1 and 8, I don't know how many at design time.
  2. I must be able to especify the exact spacing between the labels.

If it wasn't for 2, this wouldn't be so hard, after some thinking I came up with this:

private void panel1_Resize(object sender, EventArgs e)
{
    int position = 1;
    foreach (Label l in panel1.Controls)
    {
        CenterToParent(l, panel1.Controls.Count, position);
        position++;
    }
}

private static void CenterToParent(Label lbl, int qty, int pos)
{
    lbl.SetBounds((lbl.Parent.Bounds.Width - lbl.Width) * pos / (qty + 1),
                    lbl.Location.Y, lbl.Width, lbl.Height);
}

But this way the space between labels will change as the panel's width changes and this gap must be of a fixed size. That's also why I can't simply use a TableLayoutPanel.

PS: If you would be so kind, it would be very enlightening if you make the CenterToParent method work if I don't know the object type (just that it does have the same properties). I have a feeling that I will need this in a near future and I don't have a clue on how to do it.

Upvotes: 1

Views: 1750

Answers (1)

user203570
user203570

Reputation:

At least for your second question, just change the Label lbl to Control ctrl. That can take an arbitrary control and center it on its parent, assuming it was one. You may wish to check for that condition.

Update:

I thought about your issue a bit more. First, your application will crash during your foreach loop if any non-Label controls are on your panel. Change it to foreach (Control ctrl in panel1.Controls). This also uses my original answer to your second question.

Your basic problem is that given some number of controls, they must be horizontally centered on their parent and evenly spaced apart. The total width of this is: (control1.Width + offset) + (control2.Width + offset) ... (controlN.Width + offset) - offset. The x coordinate (startX) of this if (Parent.Width / 2) - (TotalWidth / 2). Now that you know the x coordinate, you can start laying out your controls like so:

control1.Left = startX;
control2.Left = control1.Right + offset
controlN.Left = control(N-1).Right + offset

As real code maybe like this:

const int Offset = 8; // for example
int totalWidth = panel1.Controls.Cast<Control>().Aggregate(0, (value, ctrl) => value + ctrl.Width + Offset);

for (int index = 0; index < panel1.Controls.Count; index++)
{
    Control current = panel1.Controls[index];

    if (index == 0)
    {
        current.Left = startX;
    }

    else
    {
        current.Left = panel1.Controls[index-1].Right + Offset;
    }
}

I admittedly did not test this out, but maybe you'll get it working from here. Good luck.

Upvotes: 1

Related Questions