Lazarus控件中控件尺寸变化的处理机制

TControl类通过Left、Top、Width和Height四个属性定义了控件的尺寸和位置信息,对这四个属性以及BoundsRect的修改(GetBoundsRect和SetBoundsRect函数也是操作这四个变量)会调用SetBounds过程(SetBounds过程亦可手动调用)重新设置控件的相关变量。

当通过SetBounds过程(KeepBase=false)或布局器(KeepBase=true)修改控件尺寸和位置的时候,下一步会调用ChangeBounds过程。在ChangeBounds过程中会首先检查和修正传入的尺寸和位置数据

control.inc

  // constraint the size
  DoConstrainedResize(ALeft, ATop, AWidth, AHeight);

然后再调用DoSetBounds函数把修正过的数据实际存入控件的相关变量中

control.inc

  DoSetBounds(ALeft, ATop, AWidth, AHeight);

最后通知用户控件的尺寸和位置发生了改变

control.inc

  // notify user about resize
  if (not (csLoading in ComponentState)) then
  begin
    Resize;
    CheckOnChangeBounds;
    // for delphi compatibility send size/move messages
    PosSizeKept;
    SendMoveSizeMessages(SizeChanged,PosChanged);
  end;

因此如果在TControl的子类中覆盖ChangeBounds的话,需要注意传入的ALeft、ATop、AWidth、AHeight参数并不一定是最终的实际数据。

DoSetBounds是一个较为底层的过程,它对关于控件尺寸和位置的变量进行实际操作,因此尽量避免直接调用它,而让LCL负责。当覆盖这个过程的时候,不要在其中进行绘制工作,而是在OnPaint事件中调用Invalidate过程,或覆盖Paint过程。

Resize过程会触发OnResize事件,而为了与Delphi兼容,也会通过SendMoveSizeMessages过程发送尺寸和位置变化的消息。

继承自TControl的控件可以覆盖这个虚方法发送指定的消息。在TWinControl中,该方法会发送LM_SIZE和LM_MOVE消息。在Windows环境下,这两个消息的定义与WM_SIZE和WM_MOVE消息相同,但TLMMOVE和TWMMOVE消息结构略有差异。

messages.inc

  WM_MOVE = 3;
  WM_SIZE = 5;

lmessages.pp

  LM_MOVE = $0003;
  LM_SIZE = $0005;

因此如有必要,继承自TWinControl的控件也可以通过处理这两个消息来响应尺寸和位置变化。

  private
    procedure WMSize(var Message: TWMSize); message WM_SIZE;

需要注意的是,在特定情况下(not (csLoading in ComponentState)),这个消息不会被发送。

参考:

Lazarus Wiki

Custom Controls

When you write your own control, you can override and fine tune many parts of the LCL autosizing.
SetBounds, ChangeBounds, DoSetBounds

SetBounds is called when the properties Left, Top, Width, Height, BoundsRect is set or the user calls it directly. SetBounds updates the BaseBounds and BaseParentClientSize, which are used by anchoring to keep the distance. For example loading a Form with TMemo and the lfm contains TMemo’s Left and Width, then SetBounds is called two times for the memo. When the user maximizes a window, SetBounds is called for the form, but not for the Memo, keeping the BaseBounds of the Memo. If the Memo is anchored to the right, the Width of the Memo is changed based on the BaseBounds and BaseParentClientSize. Keep in mind that the given aLeft, aTop, aWidth, aHeight might not be valid and will be changed by the LCL before applied. Delphi calls SetBounds more often. SetBounds calls ChangeBounds with KeepBase=false.

ChangeBounds is called whenever the position or size of the control is set, either via the properties or by the layouter of the LCL. SetBounds calls internally ChangeBounds with KeepBase=false, while the LCL layouter calls it with KeepBase=true. Override this for code that might change the preferred size or resizes other controls. Keep in mind that the given aLeft, aTop, aWidth, aHeight might not be valid and will be changed by the LCL before applied. You can call this function.

DoSetBounds is a low level function to set the private variables FLeft, FTop, FWidth, FHeight. Do not call this function, only the LCL calls it. It also updates FClientWidth and FClientHeight accordingly. Override this to update the content layout of the control, for example scroll bars. As always: do not paint here, but call Invalidate and paint in OnPaint or override Paint.

DoAdjustClientRectChange is called by the LCL and the LCL interface, when the ClientRect has changed and the Width and Height were kept.

WMSize exists for Delphi/VCL compatibility. It is called by the LCL interface and on every change of bounds.

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值