Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当我的窗体比屏幕大时,为什么我的Delphi窗体控件会被裁剪?_Delphi_Delphi Xe2 - Fatal编程技术网

当我的窗体比屏幕大时,为什么我的Delphi窗体控件会被裁剪?

当我的窗体比屏幕大时,为什么我的Delphi窗体控件会被裁剪?,delphi,delphi-xe2,Delphi,Delphi Xe2,情况是这样的: 我已经创建了一个Delphi(XE2)表单 它上面是一个拉伸的TGroupBox(或其他控件),因此它占据了窗体顶部的整个宽度 在TGroupBox上设置了右锚(除了左锚和上锚之外) 表单宽度设置为1200px(用于说明该点) 如果我在Screen.Width属性大于1200px的监视器上运行此应用程序(我在运行时没有任何DPI虚拟化AFAIK),则TGroupBox会按预期呈现 然而。。如果监视器的宽度小于1200px,则无论如何调整窗体大小,屏幕上都会缺少控件的右侧部分

情况是这样的:

  • 我已经创建了一个Delphi(XE2)表单
  • 它上面是一个拉伸的TGroupBox(或其他控件),因此它占据了窗体顶部的整个宽度
  • 在TGroupBox上设置了右锚(除了左锚和上锚之外)
  • 表单宽度设置为1200px(用于说明该点)
如果我在
Screen.Width
属性大于1200px的监视器上运行此应用程序(我在运行时没有任何DPI虚拟化AFAIK),则
TGroupBox
会按预期呈现

然而。。如果监视器的宽度小于1200px,则无论如何调整窗体大小,屏幕上都会缺少控件的右侧部分

我已经用
覆盖覆盖了表单的
Create()
方法指令,并验证我正确设置了
宽度
属性,但是控件仍然被裁剪

有人能建议如何:

a) 设置窗体的宽度属性,使其影响子组件的位置或


b) 建议在呈现表单后强制重新显示所有子组件的方法?

跟踪代码以查看发生了什么,我提出了以下调整

procedure TForm1.WMWindowPosChanging(var Message: TWMWindowPosChanging);
var
  MessageWidth: Integer;
begin
  MessageWidth := Message.WindowPos.cx;
  inherited;
  if MessageWidth > Message.WindowPos.cx then
    GroupBox1.Width := GroupBox1.Width - MessageWidth + Message.WindowPos.cx;
end;
这不是一个广义的解决方案,但它清楚地说明了问题所在。VCL要求窗体的窗口大小,但操作系统不允许,因为它比桌面大。从那时起,窗体将恢复锚定子控件,其设计时指定的宽度大于窗体的客户端宽度,因此子控件的右侧溢出

另一个解决方案是重写对
WM_GETMINMAXINFO
消息的处理,让操作系统授予所请求的宽度

procedure TForm1.WMGetMinMaxInfo(var Message: TWMGetMinMaxInfo);
begin
  inherited;
  Message.MinMaxInfo.ptMaxTrackSize.X := 1200;
end;
这可能不是一个好的解决方案,因为这样表单就会比桌面大

关于您的“a”和“b”项,我认为“b”是不可能的,或者至少不可能让VCL自己重新发布,因为VCL将应用锚定规则推迟到组件(表单)加载完成之后。此时,窗体的宽度与设计时宽度不同,但子控件的位置不受影响。再多的强制布局也不会使它们再次同步

但是,如果您自己的代码保留对设计时宽度的引用,则应该可以从头开始重新计算所有内容。下面是不完整的代码

type
  TForm1 = class(TForm)
    ..
  private
    FAdjustShrinkWidth, FAdjustShrinkHeight: Integer;
  protected
    procedure Loaded; override;
  public
    procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer;
      AHeight: Integer); override;
  end;

...

procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  TrackWidth, TrackHeight: Boolean;
begin
  TrackWidth := AWidth = 1200;
  TrackHeight := AHeight = ??;
  inherited;
  if TrackWidth and (Width < AWidth) then
    FAdjustShrinkWidth := AWidth - Width;
  if TrackHeight and (Height < AHeight) then
    FAdjustShrinkHeight := AHeight - Height;
end;

procedure TForm1.Loaded;

  procedure ReadjustControlAnchors(Control: TWinControl);
  var
    i: Integer;
  begin
    for i := 0 to Control.ControlCount - 1 do
      if (akRight in Control.Controls[i].Anchors) or (akBottom in Control.Controls[i].Anchors) then begin
        Control.Controls[i].Left := // some complex calculation depending on the anchors set;
        Control.Controls[i].Top := // same as above;
        Control.Controls[i].Width := // same as above;
        Control.Controls[i].Height := // same as above;
        if (Control.Controls[i] is TWinControl) and (TWinControl(Control.Controls[i]).ControlCount > 0) then
          ReadjustControlAnchors(TWinControl(Control.Controls[i]));
      end;
  end;

begin
  inherited;
  ReadjustControlAnchors(Self);
end;
类型
TForm1=类(TForm)
..
私有的
FAdjustShrinkWidth、FAdjustShrinkHeight:整数;
受保护的
加载程序;推翻
公众的
过程SetBounds(ALeft:Integer;top:Integer;AWidth:Integer;
AHeight:整数);推翻
结束;
...
程序TForm1.SetBounds(ALeft、top、AWidth、ahheight:整数);
变量
TrackWidth、TrackHeight:布尔值;
开始
轨道宽度:=AWidth=1200;
轨道高度:=AHHEIGH=??;
继承;
如果轨道宽度和(宽度<宽度),则
FAdjustShrinkWidth:=AWidth—宽度;
如果轨道高度和(高度0),则
重新调整控制锚(TWinControl(Control.Controls[i]);
结束;
结束;
开始
继承;
重新调整锚(自我);
结束;
我不知道如何填写上面代码中的空白。为了模拟VCL锚定,可能必须读取和跟踪VCL代码

我想不出“a”有什么好处


更新:

VCL实际上给控件留下了一个后门,让它在其直系子控件锚定时,对其父控件的大小撒谎。解释有点不同:

UpdateControlriginalParentSize是一个受保护的方法,用于更新 父控件的原始大小。它在内部用于更新 控制的锚定规则

我们可以使用它告诉groupbox预期的原始大小

type
  TForm1 = class(TForm)
    ..
  private
    FWidthChange, FHeightChange: Integer;
  protected
    procedure UpdateControlOriginalParentSize(AControl: TControl;
      var AOriginalParentSize: TPoint); override;
  public
    procedure SetBounds(ALeft: Integer; ATop: Integer; AWidth: Integer;
      AHeight: Integer); override;
  end;

...

procedure TForm1.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
var
  RequestedWidth, RequestedHeight: Integer;
begin
  RequestedWidth := AWidth;
  RequestedHeight := AHeight;
  inherited;
  if csLoading in ComponentState then begin
    if RequestedWidth <> Width then
      FWidthChange := Width - AWidth;
    if RequestedHeight <> Height then
      FHeightChange := Height - AHeight;
  end;
end;

procedure TForm1.UpdateControlOriginalParentSize(AControl: TControl;
  var AOriginalParentSize: TPoint);
begin
  inherited;
  if akRight in AControl.Anchors then
    AOriginalParentSize.X := AOriginalParentSize.X - FWidthChange;
  if akBottom in AControl.Anchors then
    AOriginalParentSize.Y := AOriginalParentSize.Y - FHeightChange;
end;
类型
TForm1=类(TForm)
..
私有的
FWidthChange,FHeightChange:整数;
受保护的
过程updateControl-LoginalParentSize(AControl:TControl;
var AOriginalParentSize:TPoint);推翻
公众的
过程SetBounds(ALeft:Integer;top:Integer;AWidth:Integer;
AHeight:整数);推翻
结束;
...
程序TForm1.SetBounds(ALeft、top、AWidth、ahheight:整数);
变量
RequestedWidth、RequestedHeight:整数;
开始
RequestedWidth:=AWidth;
请求的高度:=AHeight;
继承;
如果CSC在ComponentState中加载,则开始
如果请求宽度,则
FWidthChange:=宽度-宽度;
如果要求高度,则
FHeightChange:=高度-高度;
结束;
结束;
过程TForm1.updateControlriginalParentSize(AControl:TControl;
var AOriginalParentSize:TPoint);
开始
继承;
如果Aktright在AControl.Anchors中,则
AOriginalParentSize.X:=AOriginalParentSize.X-FWidthChange;
如果Aktown在AControl.Anchors中,则
AOriginalParentSize.Y:=AOriginalParentSize.Y-FHeightChange;
结束;

我再次注意到,这只会影响表单的直接子级。如果groupbox承载锚定右侧和底部的控件,它还必须重写相同的方法

还要注意,这不会撤消窗体宽度已更改的事实。如果有一个左非国大的话