Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
KANSoftWare

Оптимизация макета вручную: избегайте проблем с выравниванием и якорями.

Delphi , Программа и Интерфейс , Размеры и Положение

 

В разработке приложений на Delphi с использованием Object Pascal часто возникают сложности с масштабированием интерфейса, особенно при работе с различными разрешениями экрана. В этой статье мы разберем конкретную проблему, описанную на форуме, и предложим несколько решений.

Проблема: компонент не появляется там, где должен

Пользователь heebiejeebies столкнулся с необычной проблемой: при изменении разрешения интерфейса один конкретный компонент (TBCRoundedImage с именем MainHomeBtn1) отображался на 15 пикселей ниже, чем должен был. Особенность заключалась в том, что проблема проявлялась только при переключении разрешения, когда компонент не был виден (находился на неактивной вкладке).

Анализ исходного кода

Пользователь реализовал собственный механизм масштабирования с использованием TStringGrid, где хранились данные о размерах и позициях компонентов для разных разрешений. Вот ключевые части его кода:

procedure TMainForm.ApplyScaling(Resolution: String);
var
  Grid: TStringGrid;
  i, j: Integer;
  CompName, PropName, PropValue: String;
  Comp: TComponent;
  PropInfo: PPropInfo;
  ScreenWidth, ScreenHeight: Integer;
begin
  // Установка размера формы в зависимости от разрешения
  case Resolution of
    '4K': begin ScreenWidth := 3200; ScreenHeight := 1750; end;
    'HiRes': begin ScreenWidth := 2560; ScreenHeight := 1540; end;
    'HD': begin ScreenWidth := 1920; ScreenHeight := 1050; end;
    'LoRes': begin ScreenWidth := 1366; ScreenHeight := 738; end;
  else
    Exit; // Некорректное разрешение
  end;

  MainForm.Width := ScreenWidth;
  MainForm.Height := ScreenHeight;

  // Выбор правильной таблицы в зависимости от ОС и разрешения
  case CurrentOS of
    osWindows:
      case Resolution of
        '4K': Grid := ScalingData.WPanels4k;
        'HiRes': Grid := ScalingData.WPanelsHiRes;
        'HD': Grid := ScalingData.WPanelsHD;
        'LoRes': Grid := ScalingData.WPanelsLoRes;
      end;
    // ... аналогично для других ОС
  end;

  // Применение масштабирования к компонентам
  for i := 1 to Grid.RowCount - 1 do
  begin
    CompName := Grid.Cells[0, i];
    Comp := MainForm.FindComponent(CompName);

    if Assigned(Comp) then
    begin
      for j := 1 to Grid.ColCount - 1 do
      begin
        PropName := Grid.Cells[j, 0];
        PropValue := Grid.Cells[j, i];

        if PropName = 'Type' then Continue;

        // Специальная обработка для некоторых компонентов
        if (Comp is TBGRALabel) and (PropName = 'Font.Size') then
          TBGRALabel(Comp).Font.Size := StrToIntDef(PropValue, 0);

        // Общая обработка свойств
        if (PropValue <> '') then
        begin
          PropInfo := GetPropInfo(Comp.ClassInfo, PropName);
          if Assigned(PropInfo) then
          begin
            case PropInfo^.PropType^.Kind of
              tkInteger, tkInt64:
                SetPropValue(Comp, PropName, StrToIntDef(PropValue, 0));
              tkFloat:
                SetPropValue(Comp, PropName, StrToFloatDef(PropValue, 0.0));
              tkString, tkLString, tkAString, tkWString, tkUString:
                SetPropValue(Comp, PropName, PropValue);
            end;
          end;
        end;
      end;
    end;
  end;
end;

Возможные причины проблемы

  1. Проблемы с родительским контейнером: Компонент может быть привязан не к той вкладке, где ожидается.
  2. Конфликт с системным масштабированием: Включенное системное масштабирование (LCL Scaling) может конфликтовать с ручным управлением.
  3. Особенности работы TBCRoundedImage: Этот компонент может иметь внутреннюю логику позиционирования.
  4. Проблемы с обновлением визуализации: При скрытии/показе компонента может не обновляться его позиция.

Решения и рекомендации

1. Проверка родительского контейнера

Убедитесь, что компонент действительно находится на нужной вкладке:

if MainHomeBtn1.Parent <> ExpectedTabSheet then
  MainHomeBtn1.Parent := ExpectedTabSheet;

2. Отключение системного масштабирования

Как советовал wp, отключите встроенное масштабирование: - В настройках проекта: "Use LCL Scaling (High DPI)" → Off - Свойство Scaled формы → False

3. Альтернативный подход к масштабированию

Вместо полного ручного управления можно использовать комбинацию Anchor и Constraints:

// Установка якорей (отключить, если используете ручное позиционирование)
MainHomeBtn1.Anchors := [akLeft, akTop];

// Установка ограничений
MainHomeBtn1.Constraints.MinWidth := 100;
MainHomeBtn1.Constraints.MinHeight := 50;
MainHomeBtn1.Constraints.MaxWidth := 200;
MainHomeBtn1.Constraints.MaxHeight := 100;

4. Принудительное обновление позиции

Добавьте принудительное обновление позиции после масштабирования:

procedure TMainForm.ApplyScaling(Resolution: String);
begin
  // ... существующий код ...

  // Принудительное обновление проблемного компонента
  if Assigned(MainHomeBtn1) then
  begin
    MainHomeBtn1.Top := MainHomeBtn1.Top + 1;
    MainHomeBtn1.Top := MainHomeBtn1.Top - 1;
    MainHomeBtn1.Invalidate;
  end;
end;

5. Решение с OnChange вкладки

Как временное решение, пользователь добавил вызов ApplyScaling в событие OnChange вкладки:

procedure TMainForm.TabSheetChange(Sender: TObject);
begin
  ApplyScaling(CurrentResolution);
end;

Альтернативный подход: использование относительных координат

Вместо абсолютных значений в таблице можно хранить относительные координаты:

procedure TMainForm.ApplyRelativeScaling;
var
  i: Integer;
  Comp: TControl;
  NewLeft, NewTop, NewWidth, NewHeight: Integer;
begin
  for i := 0 to ComponentCount - 1 do
  begin
    if Components[i] is TControl then
    begin
      Comp := TControl(Components[i]);

      // Расчет новых координат относительно размера формы
      NewLeft := Round(Comp.Tag * Self.Width / 100); // Хранить процент в Tag
      NewTop := Round((Comp.Tag shr 8) * Self.Height / 100);
      NewWidth := Round((Comp.Tag shr 16) * Self.Width / 100);
      NewHeight := Round((Comp.Tag shr 24) * Self.Height / 100);

      Comp.SetBounds(NewLeft, NewTop, NewWidth, NewHeight);
    end;
  end;
end;

Заключение

Проблемы с позиционированием компонентов в Delphi при ручном масштабировании могут быть вызваны различными факторами. В данном случае наиболее вероятными причинами являются:
1. Конфликт с системным масштабированием
2. Особенности работы компонента TBCRoundedImage
3. Проблемы с обновлением визуализации при переключении вкладок

Рекомендуемые решения:
- Отключить системное масштабирование (LCL Scaling)
- Проверить и явно установить родительский контейнер
- Добавить принудительное обновление позиции проблемного компонента
 

Создано по материалам из источника по ссылке.

Context описывает проблемы с позиционированием компонентов в Delphi и предлагает решения для масштабирования интерфейса на разных разрешениях экрана.


Комментарии и вопросы

Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.


:: Главная :: Размеры и Положение ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-12-22 20:14:06
2025-05-21 07:31:42/0.006289005279541/0