Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Общие вопросы > Графические разрешения


Автор: Alex_Alexin 17.12.2006, 18:33
Интерфейс формы прописан под 800x600. Как грамотно прописать масштабирование расположения компонентов формы и их размеров для различных графических разрешений монитора?

Автор: Snowy 17.12.2006, 22:01
На торри есть компоненты для масштабирования

Добавлено @ 22:03 
http://www.torry.net/pages.php?id=97

Автор: jaAlex 18.12.2006, 01:01
Код

procedure AutoScale(MForm: TForm);
const
  cScreenWidth: integer = 800;
  cScreenHeight: integer = 600;
  cPixelsPerInch: integer = 96;
  cFontHeight: integer = -11;
var
  i: integer;
begin
  if (Screen.width <> cScreenWidth) or (Screen.PixelsPerInch <>
    cPixelsPerInch) then
  begin 
    MForm.scaled := TRUE;
    MForm.height := MForm.height * screen.Height div cScreenHeight; 
    MForm.width := MForm.width * screen.width div cScreenWidth;
    MForm.ScaleBy(screen.width, cScreenWidth);
  end;
  if (Screen.PixelsPerInch <> cPixelsPerInch) then
  begin
    for i := MForm.ControlCount - 1 downto 0 do
      TFooClass(MForm.Controls[i]).Font.Height :=
        (MForm.Font.Height div cFontHeight) *
        TFooClass(MForm.Controls[i]).Font.Height;
  end;
end;
...
AutoScale(Form1);

Вот как - то так.

Автор: Alexeis 18.12.2006, 10:52
На самом деле, вопрос не такой очевидный, и не имеет однозначного решения. По хорошему вместе с размерами контролов необходимо менять еще и размер шрифта, иначе при переходе, на большие разрешения он становится мелким.  Шрифт также имеет ограничения по уменьшению, после которого он становится не плохо читабельным. Потому как мне кажется, самое надежное привязываться именно к размеру шрифта. А то ведь представьте уменьшите вы размер контрола не изменив размер шрифта, тогда есть все шансы обрезать текст не поместившийся в этой строке. Возможна и другая ситуация, когда не специфические контролы не поддаются масштабированию или эта операция для них не желательна, например скролбары. Масштабирование формы имеет свои ограничения, так что желательно при проектировании изначально форма не занимала весь экран, т.е. чтобы она не обрезалась при меньших разрешениях.

Я делал так при создании формы заносил параметры всех контролов MemoryStream.
Код

procedure TForm1.FormCreate(Sender: TObject);
 var
     a, i : Integer;
     d    : TDevMode;
     p    : pansichar;
     b    : boolean;
     
begin
  OrigSize := TMemoryStream.Create;
  OrigSize.Seek(0, soFromBeginning);

  if ComponentCount <> 0
  then
    for i := 0 to ComponentCount - 1
    do
      Begin
        if (Components[i].ClassType = TButton) or
           (Components[i].ClassType = TRadioGroup)
        then
          Begin
            OrigSize.Write(TButton(Components[i]).Left, 4);
            OrigSize.Write(TButton(Components[i]).Top , 4);
            OrigSize.Write(TButton(Components[i]).Width , 4);
            OrigSize.Write(TButton(Components[i]).Height , 4);

          end;

        if (Components[i].ClassType = TComboBox) or
           (Components[i].ClassType = TSpinEdit) or
           (Components[i].ClassType = TCheckBox) or
           (Components[i].ClassType = TLabel)
        then
          Begin
            OrigSize.Write(TButton(Components[i]).Left, 4);
            OrigSize.Write(TButton(Components[i]).Top , 4);
            OrigSize.Write(TButton(Components[i]).Width , 4);
          end;
      end;


А после при изменении разрешения или если оно просто отличалось от исходного пересчитывал их каждый раз сначала шрифт, который уже не может меняться при разрешении меньше 800х600 и кроме того меняется очень грубо. А уже после этого пересчитывал масштабный параметр. Таким образом текст всегда будет одинаково помещаться на контролах при любом разрешении экрана.

Код

 if Screen.Height < 600
  then
    Font.Height := -9
  else
    Font.Height := -Round(11 * Screen.Height / 768);

  Scale := Font.Height / -11;

  CanResize := True;
    CheckBox1.Checked := False;
    Form1.Width  := Round(252 * Scale) + 8;
    Form1.Height := Round(201 * Scale) + 34;
    Form1.Top    := Round((Screen.Height - Form1.Height) / 2);
    Form1.Left   := Round((Screen.Width  - Form1.Width)  / 2);
  CanResize := False;

  OrigSize.Seek(0, soFromBeginning);

  if ComponentCount <> 0
  then
    for i := 0 to ComponentCount - 1
    do
      Begin
        if (Components[i].ClassType = TButton) or
           (Components[i].ClassType = TRadioGroup)
        then
          Begin
            OrigSize.Read(temp, 4);
            TButton(Components[i]).Left := Round(temp * Scale);

            OrigSize.Read(temp , 4);
            TButton(Components[i]).Top := Round(temp * Scale);

            OrigSize.Read(temp , 4);
            TButton(Components[i]).Width := Round(temp * Scale);
            
            OrigSize.Read(temp , 4);
            TButton(Components[i]).Height := Round(temp * Scale);
          end;

        if (Components[i].ClassType = TComboBox) or
           (Components[i].ClassType = TSpinEdit) or
           (Components[i].ClassType = TCheckBox) or
           (Components[i].ClassType = TLabel)
        then
          Begin
            OrigSize.Read(temp, 4);
            TButton(Components[i]).Left := Round(temp * Scale);

            OrigSize.Read(temp , 4);
            TButton(Components[i]).Top := Round(temp * Scale);

            OrigSize.Read(temp , 4);
            TButton(Components[i]).Width := Round(temp * Scale);

            TButton(Components[i]).Font.Height := Font.Height;
          end;
      end;


Данный метод имеет тот недостаток, что не позволяет удалять компоненты. Это можно исправить если вносить в поток еще и их имена. Если контролы будут создаваться во время работы, то их прийдется предварительно туда же в поток прописывать или после создания или до создания.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)