Delphi 更改窗体大小后重新居中窗体

Delphi 更改窗体大小后重新居中窗体,delphi,resize,Delphi,Resize,我有一个组合框,它有两个选项,这两个选项会触发窗体的大小调整。我的想法是根据选择隐藏和显示其他控件 当我更改窗体宽度时,大小会根据需要更改,但是窗体现在不再位于屏幕中央。我可以在更改窗体宽度时前后移动窗体的XY位置吗 procedure TReportFrm.SpecialFilesComboBoxChange(Sender: TObject); begin if(SpecialFilesComboBox.ItemIndex = 0) then begin //No special

我有一个组合框,它有两个选项,这两个选项会触发窗体的大小调整。我的想法是根据选择隐藏和显示其他控件

当我更改窗体宽度时,大小会根据需要更改,但是窗体现在不再位于屏幕中央。我可以在更改窗体宽度时前后移动窗体的XY位置吗

procedure TReportFrm.SpecialFilesComboBoxChange(Sender: TObject);
begin
  if(SpecialFilesComboBox.ItemIndex = 0) then begin
    //No special files
    Width := 412;
    Height := 423;
    ...
  end
  else begin
    //Yes special files
    Width := 893;
    Height := 423;
    ...
  end;
end;

一个非常简单的ReCenter函数可能如下所示:

procedure TReportFrm.ReCenter;
var
  LRect: TRect;
  X, Y: Integer;
begin
  LRect := Screen.WorkAreaRect;
  X := LRect.Left + (LRect.Right - LRect.Left - Width) div 2;
  Y := LRect.Top + (LRect.Bottom - LRect.Top - Height) div 2;
  SetBounds(X, Y, Width, Height);
end;

procedure TReportFrm.SpecialFilesComboBoxChange(Sender: TObject);
begin
  if(SpecialFilesComboBox.ItemIndex = 0) then begin
    //No special files
    Width := 412;
    Height := 423;
    ...
  end
  else begin
    //Yes special files
    Width := 893;
    Height := 423;
    ...
  end;
  ReCenter;
end;
NewBoundsRect := Rect(NewLeft, NewTop, NewLeft+NewWidth, NewTop+NewHeight);
MakeAppearOnScreen(NewBoundsRect);
BoundsRect := NewBoundsRect;

它将窗口居中于屏幕的工作区域,您可能希望将其居中于其他参考位置,在这种情况下,由您确定有意义的矩形。

多监视器系统现在很常见。放置在屏幕中央可能会将表单分散到多个监视器上。那是不可取的

所以我把表格放在显示器的中心:

R := Form.Monitor.WorkAreaRect;
Form.Left := (R.Left+R.Right-Form.Width) div 2;
Form.Top := (R.Top+R.Bottom-Form.Height) div 2;
正如@bummi指出的,你可以写:

Form.Position := poScreenCenter;
这几乎如你所愿。我将在屏幕上使窗体居中。但是,它总是选择默认监视器。因此,使用该代码可能会导致表单移动到不同的监视器上,我认为这是不可取的

您可以决定从四面增加或缩小形状,而不是将形状强制到中心:

procedure TReportFrm.SpecialFilesComboBoxChange(Sender: TObject);
var
  NewLeft, NewTop, NewWidth, NewHeight: Integer;
begin
  if(SpecialFilesComboBox.ItemIndex = 0) then begin
    //No special files
    NewWidth := 412;
    NewHeight := 423;
    ...
  end
  else begin
    //Yes special files
    NewWidth := 893;
    NewHeight := 423;
    ...
  end;

  NewLeft := Left + (Width-NewWidth) div 2;
  NewTop := Top + (Top-NewHeight) div 2;
  NewBoundsRect := Rect(NewLeft, NewTop, NewLeft+NewWidth, NewTop+NewHeight);
  BoundsRect := NewBoundsRect;
end;
如果你想变得非常可爱,你可以调整bounds rect,这样新大小和定位的表单就不会离开显示器的边缘

procedure MakeAppearOnScreen(var Rect: TRect);
const
  Padding = 24;
var
  Monitor: HMonitor;
  MonInfo: TMonitorInfo;
  Excess, Width, Height: Integer;
begin
  Monitor := MonitorFromPoint(Point((Rect.Left+Rect.Right) div 2, (Rect.Top+Rect.Bottom) div 2), MONITOR_DEFAULTTONEAREST);
  if Monitor=0 then begin
    exit;
  end;
  MonInfo.cbSize := SizeOf(MonInfo);
  if not GetMonitorInfo(Monitor, @MonInfo) then begin
    exit;
  end;
  Width := Rect.Right-Rect.Left;
  Height := Rect.Bottom-Rect.Top;

  Excess := Rect.Right+Padding-MonInfo.rcWork.Right;
  if Excess>0 then begin
    dec(Rect.Left, Excess);
  end;
  Excess := Rect.Bottom+Padding-MonInfo.rcWork.Bottom;
  if Excess>0 then begin
    dec(Rect.Top, Excess);
  end;
  Excess := MonInfo.rcWork.Left+Padding-Rect.Left;
  if Excess>0 then begin
    inc(Rect.Left, Excess);
  end;
  Excess := MonInfo.rcWork.Top+Padding-Rect.Top;
  if Excess>0 then begin
    inc(Rect.Top, Excess);
  end;
  Rect.Right := Rect.Left+Width;
  Rect.Bottom := Rect.Top+Height;
end;
然后,前面的代码示例将更改如下:

procedure TReportFrm.ReCenter;
var
  LRect: TRect;
  X, Y: Integer;
begin
  LRect := Screen.WorkAreaRect;
  X := LRect.Left + (LRect.Right - LRect.Left - Width) div 2;
  Y := LRect.Top + (LRect.Bottom - LRect.Top - Height) div 2;
  SetBounds(X, Y, Width, Height);
end;

procedure TReportFrm.SpecialFilesComboBoxChange(Sender: TObject);
begin
  if(SpecialFilesComboBox.ItemIndex = 0) then begin
    //No special files
    Width := 412;
    Height := 423;
    ...
  end
  else begin
    //Yes special files
    Width := 893;
    Height := 423;
    ...
  end;
  ReCenter;
end;
NewBoundsRect := Rect(NewLeft, NewTop, NewLeft+NewWidth, NewTop+NewHeight);
MakeAppearOnScreen(NewBoundsRect);
BoundsRect := NewBoundsRect;

PS我不能在
if
语句之后简单地调用它,我将得到一个访问冲突:
BugReportFrm.Position:=poMainFormCenter是否分配了BugReportFrm?您的代码正在显示TReportFrm。只是不要使用实例:Position:=poMainFormCenter;只需根据需要设置顶部
和左侧。从Monitor.WorkAreaRectperfect计算。这是我最近得到的最好/最直接的德尔菲解决方案,谢谢。这里的数学是错的。只有当工作区域顶部和左侧均为零时,它们才起作用。工作区的中心是(左+右)2区。你的减号错了。代码还否认存在多监视器系统。@David噢,天哪。。。我不确定屏幕的左/顶是否与0,0不同,但我更新了答案。如上所述,它将表单集中到屏幕工作区,并在回答中向您展示如何获取表单监视器的工作区。我不同意你提出的(左+右)div2解决方案,你真的确定吗?我手边没有其他显示器要测试。你修正了数学错误,但有点混乱。“不必再提左边了。@大卫,你是对的,但我的大脑现在喜欢这样看。”Das就不同设置而言,位置可以按需要工作,我不认为有必要重新实现。@bummi位置只适用于我认为表单的初始显示。我不能谈论D7之前的版本,但这会起作用:过程TForm1.Button1Click(发件人:TObject);开始位置:=位置中心;结束@谢谢你。我不知道。遗憾的是,
poscreencecenter
似乎不适合多显示器设置。我讨厌跳窗。IMHO,一旦调整了窗口的大小,将其强制在监视器工作区域的边界内就足够了(答案的最后一部分)。