Как горизонтально центрировать несколько объектов внутри данного контейнера?

#c# #winforms #user-interface

#c# #winforms #пользовательский интерфейс

Вопрос:

Я потратил весь день, пытаясь решить эту проблему, но без удовлетворительных результатов.

Мне нужно центрировать некоторые метки внутри их контейнера (панели). Если бы была только одна метка, это было бы проще простого, но жизнь нелегка, и я должен написать метод центрирования нескольких объектов и преодолеть две проблемы:

  1. Это может быть любое количество меток от 1 до 8, я не знаю, сколько во время разработки.
  2. Я должен быть в состоянии указать точное расстояние между метками.

Если бы не 2, это было бы не так сложно, после некоторых размышлений я пришел к следующему:

 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);
}
  

Но таким образом пространство между метками будет меняться по мере изменения ширины панели, и этот промежуток должен быть фиксированного размера. Вот почему я также не могу просто использовать TableLayoutPanel.

PS: Если вы будете так любезны, было бы очень полезно, если бы вы заставили метод CenterToParent работать, если я не знаю тип объекта (только то, что он имеет те же свойства). У меня такое чувство, что мне это понадобится в ближайшем будущем, и я понятия не имею, как это сделать.

Ответ №1:

По крайней мере, для вашего второго вопроса просто измените Label lbl на Control ctrl . Это может взять произвольный элемент управления и центрировать его на его родительском элементе, предполагая, что это был один. Возможно, вы захотите проверить наличие этого условия.

Обновить:

Я немного подробнее подумал о вашей проблеме. Во-первых, ваше приложение завершит работу во время вашего foreach цикла, если на вашей панели будут какие-либо элементы управления, отличные от Label . Измените его на foreach (Control ctrl in panel1.Controls) . Здесь также используется мой оригинальный ответ на ваш второй вопрос.

Ваша основная проблема заключается в том, что при некотором количестве элементов управления они должны быть горизонтально центрированы на своем родительском элементе и равномерно разнесены друг от друга. Общая ширина этого составляет: (control1.Width offset) (control2.Width offset) ... (controlN.Width offset) - offset . Координата x (startX) этого if (Parent.Width / 2) - (TotalWidth / 2) . Теперь, когда вы знаете координату x, вы можете начать размещать свои элементы управления следующим образом:

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

В качестве реального кода может быть следующим:

 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;
    }
}
  

Я, по общему признанию, не тестировал это, но, возможно, вы сможете заставить это работать отсюда. Удачи.

Комментарии:

1. Это помогло, большое спасибо! Объекты были немного смещены от центра, но только потому, что последнему объекту не нужно смещение, я добавил - Offset к totalWidth , и теперь это идеально. Я знал об этом возможном сбое, но я знаю, что внутри этой панели есть только метки. Для этого последнего запроса я пытался использовать Object , но никогда не думал об использовании Control . Это очевидно. 🙂