【问题标题】:How to handle realign of components in runtime after screen resize delphi屏幕调整大小delphi后如何在运行时处理组件的重新对齐
【发布时间】:2020-02-14 14:40:54
【问题描述】:

我在 google 上进行了很多搜索,以获得有关如何解决当前问题的更清晰的信息,但我将组件的可伸缩性作为最佳答案,这……还不是我的问题。

所以,长话短说:我想在用户调整窗口大小后重新对齐表单上的组件,表单是从 SQL 查询动态填充的,这是构造函数代码:

procedure TForm2.MakeWindow;
var
  dummyMaskedit, dummyEdit: TEdit;
  dummyMemo: TMemo;
  dummyCombobox: TComboBox;
  dummyLabel: TLabel;
  dummyLBox: TListBox;
  dummybutton: TButton;
  i, f: integer;
  buffer, workarea: double;
begin
  FDQDB.Close;
  FDQDB.Open('SELECT * FROM Defs WHERE active = 1');

  i := 0;
  f := 1;
  buffer := Layout1.Width;
  workarea := Layout1.Width;
  SetLength(aMasks, 0);
  while not FDQDB.Eof do
  begin
    case AnsiIndexStr(FDQDB.FieldByName('comptype').AsString,
      ['tedit', 'tcombobox', 'tmaskedit', 'tlistbox']) of
      0: // TEdit
        begin
          dummyEdit := TEdit.Create(self);
          dummyEdit.Parent := Form2.Layout1;
          dummyEdit.Width := FDQDB.FieldByName('size').AsInteger;
          if buffer - dummyEdit.Width >= 0 then
          begin
            buffer := buffer - dummyEdit.Width - 8;
            dummyEdit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyEdit.Position.X := workarea - buffer - dummyEdit.Width + 5;
          end
          else
          begin
            inc(i);
            buffer := workarea;
            buffer := buffer - dummyEdit.Width - 8;
            dummyEdit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyEdit.Position.X := workarea - buffer - dummyEdit.Width + 5;
          end;
          dummyEdit.Name := 'field' + IntToStr(f);
          inc(f);

          dummyLabel := TLabel.Create(self);
          with dummyLabel do
          begin
            Parent := dummyEdit.Parent;
            Text := FDQDB.FieldByName('Descricao').AsString;
            Position.Y := dummyEdit.Position.Y - 17;
            Position.X := dummyEdit.Position.X;
          end;
        end;

      1: // TComboBox
        begin
          dummyCombobox := TComboBox.Create(self);
          dummyCombobox.Parent := Form2.Layout1;
          dummyCombobox.Width := FDQDB.FieldByName('size').AsInteger;
          if buffer - dummyCombobox.Width >= 0 then
          begin
            buffer := buffer - dummyCombobox.Width - 8;
            dummyCombobox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyCombobox.Position.X := workarea - buffer -
              dummyCombobox.Width + 5;
          end
          else
          begin
            inc(i);
            buffer := workarea;
            buffer := buffer - dummyCombobox.Width - 8;
            dummyCombobox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyCombobox.Position.X := workarea - buffer -
              dummyCombobox.Width + 5;
          end;
          dummyCombobox.Name := 'field' + IntToStr(f);
          dummyCombobox.Items.Delimiter := '|';
          dummyCombobox.Items.StrictDelimiter := true;
          dummyCombobox.Items.DelimitedText :=
            AnsiUpperCase(FDQDB.FieldByName('combovalue').AsString);
          inc(f);

          dummyLabel := TLabel.Create(self);
          with dummyLabel do
          begin
            Parent := dummyCombobox.Parent;
            Text := FDQDB.FieldByName('Descricao').AsString;
            Position.Y := dummyCombobox.Position.Y - 17;
            Position.X := dummyCombobox.Position.X;
          end;
        end;

      2: // TMaskEdit
        begin
          dummyMaskedit := TEdit.Create(self);
          dummyMaskedit.Parent := Form2.Layout1;
          dummyMaskedit.Width := FDQDB.FieldByName('size').AsInteger;
          if buffer - dummyMaskedit.Width >= 0 then
          begin
            buffer := buffer - dummyMaskedit.Width - 8;
            dummyMaskedit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyMaskedit.Position.X := workarea - buffer -
              dummyMaskedit.Width + 5;
          end
          else
          begin
            inc(i);
            buffer := workarea;
            buffer := buffer - dummyMaskedit.Width - 8;
            dummyMaskedit.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyMaskedit.Position.X := workarea - buffer -
              dummyMaskedit.Width + 5;
          end;
          dummyMaskedit.Name := 'field' + IntToStr(f);
          inc(f);

          SetLength(aMasks, length(aMasks) + 1);
          Masks.field := dummyMaskedit.Name;
          Masks.mask := FDQDB.FieldByName('mask').AsString;
          aMasks[length(aMasks) - 1] := Masks;

          dummyMaskedit.OnExit := MaskTextExit;

          dummyLabel := TLabel.Create(self);
          with dummyLabel do
          begin
            Parent := dummyMaskedit.Parent;
            Text := FDQDB.FieldByName('Descricao').AsString;
            Position.Y := dummyMaskedit.Position.Y - 17;
            Position.X := dummyMaskedit.Position.X;
          end;
        end;

      3: // TListBox
        begin
          dummyLBox := TListBox.Create(self);
          dummyLBox.Parent := Form2.Layout1;
          dummyLBox.Width := FDQDB.FieldByName('size').AsInteger;
          inc(i);
          buffer := workarea;
          if buffer - dummyLBox.Width >= 0 then
          begin
            buffer := buffer - dummyLBox.Width - 8;
            dummyLBox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyLBox.Position.X := workarea - buffer - dummyLBox.Width + 5;
          end
          else
          begin
            inc(i);
            buffer := workarea;
            buffer := buffer - dummyLBox.Width - 8;
            dummyLBox.Position.Y := Panel2.Position.Y + 22 + (45 * i);
            dummyLBox.Position.X := workarea - buffer - dummyLBox.Width + 5;
          end;
          dummyLBox.Name := 'field' + IntToStr(f);
          inc(f);

          SetLength(aMasks, length(aMasks) + 1);
          Masks.field := dummyLBox.Name;
          Masks.mask := FDQDB.FieldByName('mask').AsString;
          aMasks[length(aMasks) - 1] := Masks;

          dummyLabel := TLabel.Create(self);
          with dummyLabel do
          begin
            Parent := dummyLBox.Parent;
            Text := FDQDB.FieldByName('Descricao').AsString;
            Position.Y := dummyLBox.Position.Y - 17;
            Position.X := dummyLBox.Position.X;
          end;

          dummybutton := TButton.Create(self);
          with dummybutton do
          begin
            Parent := dummyLBox.Parent;
            Text := '+';
            Width := 20;
            Position.X := dummyLBox.Width + dummyLBox.Position.X + 3;
            Position.Y := dummyLBox.Position.Y;
            Name := 'ba' + dummyLBox.Name;
            OnClick := ButtonsAddClick;
          end;

          dummybutton := TButton.Create(self);
          with dummybutton do
          begin
            Parent := dummyLBox.Parent;
            Text := '-';
            Width := 20;
            Position.X := dummyLBox.Width + dummyLBox.Position.X + 3;
            Position.Y := dummyLBox.Position.Y + 28;
            Name := 'br' + dummyLBox.Name;
            OnClick := ButtonsRemClick;
          end;
        end;
    end;
    FDQDB.Next;
  end;
  FDQDB.Close;
end;

这在应用程序的窗口状态下运行良好且漂亮,此代码应用于表单的 onCreate 事件:

procedure TForm2.FormCreate(Sender: TObject);
begin
  FDCDB.Params.Database := ExtractFilePath(ParamStr(0)) + 'window.db';
  MakeWindow;
end;

第一个窗体,应用程序的主窗体,是调用具有内置在运行时组件的新窗体的窗体:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  Application.CreateForm(TForm2, Form2);
  Form2.Layout1.parent := Self.Layout1.Parent;
  Form2.Layout1.Width := Self.Layout1.Width;
end;

第二个表单有一个 TLayout,就像第一个表单一样。然后,当我创建表单时,我将第二个表单的 TLayout 带到第一个表单。到目前为止一切顺利,当应用程序以窗口模式启动时它可以工作。 但是,当我将 form1 置于全屏模式,然后单击创建 form2 的按钮时,组件保持在与窗口模式相同的位置。我尝试将工作区变量更改为这些:

Screen.width, //components behave as the application were in fullscreen the whole time
Screen.WorkAreaWidth, //same as screen.width
(Layout1.Parent as TLayout).Width, //invalid typecast
(Layout1.GetParentComponent as TLayout).Width //invalid typecast

他们都没有工作。 我希望能够根据其视觉宽度调整屏幕上组件的位置,因此如果用户在创建新表单之前调整窗口大小,则组件会正确对齐。 有人知道解决方案吗?提前致谢

【问题讨论】:

  • 表单的OnResize 是调整包含控件大小的地方。
  • 也许您可以在分配新的父级后(或调整窗口大小后)使用FMX.Controls.TControl.Realign 方法。来自文档:考虑到它们的对齐属性、边距和填充,重新对齐子级。.
  • 好的,但我不能每次用户调整画布大小时都重做整个窗口,我会在创建事件上调整组件,然后如果用户出于任何特殊原因调整窗口大小,他只需要关闭打开的表单并重新打开它们,主表单组件不会被触及,只有子表单。

标签: delphi resize firemonkey firedac


【解决方案1】:

但是当我将 form1 置于全屏模式时,然后单击 创建 form2,组件保持在与中相同的位置 窗口模式。

TForm1.SpeedButton1Click(),您调用Application.CreateForm(TForm2, Form2);,它触发TForm2.FormCreate(Sender: TObject);,它调用MakeWindow。此时Form2 只知道设计时间大小。

MakeWindow 完成后,TForm1.SpeedButton1Click() 继续:

Form2.Layout1.parent := Self.Layout1.Parent;
Form2.Layout1.Width := Self.Layout1.Width;

但这些不再影响控件的布局。

在调用MakeWindow之前需要设置Form2.Layout1.Width,例如:

procedure TForm1.SpeedButton1Click(Sender: TObject);
begin
  Application.CreateForm(TForm2, Form2);
  Form2.Layout1.parent := Self.Layout1.Parent;
  Form2.Layout1.Width := Self.Layout1.Width;
  MakeWindow; // remove it from TForm2.FormCreate()
end;

【讨论】:

    【解决方案2】:

    表单具有 ClientWidth 和 ClientHeight 属性,它们在 OnResize 中工作得很好,可以根据可用区域动态调整控件的大小。 OnResize 在窗体可见之前触发。例如有一个带有 100 边框的 Memo1:

    procedure TForm1.FormResize(Sender: TObject);
    begin
      memo1.Position.X := 100;  // Only needs to be done once but here so all code is in one spot
      memo1.Position.Y := 100;
      memo1.Width := form1.ClientWidth - 200;
      memo1.Height := form1.ClientHeight - 200;
    end;
    

    【讨论】:

    • 表单不可见,我没有触发 onShow 事件。此外,我将 MakeWindow 过程放在 onResize 事件上,组件仍然与窗口应用程序出现在同一位置。
    • 让孩子一次。在孩子的 OnResize 设置中设置事物的大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    相关资源
    最近更新 更多