{******************************************************************************} { CnPack For Delphi/C++Builder } { 中国人自己的开放源码第三方开发包 } { (C)Copyright 2001-2018 CnPack 开发组 } { ------------------------------------ } { } { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 } { 改和重新发布这一程序。 } { } { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 } { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 } { } { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 } { 还没有,可访问我们的网站: } { } { 网站地址:http://www.cnpack.org } { 电子邮件:master@cnpack.org } { } {******************************************************************************} unit CnFormScaler; {* |
================================================================================
* 软件名称:不可视工具组件包
* 单元名称:在不同的屏幕DPI下,自动调整窗体的字体和大小的组件单元
* 单元作者:Shenloqi, liuzhongwu
* 备    注:
    Scaled = False并不是很好的解决不同分辨率的显示不同的方法,因为这样程序的外观
  跟用户所想看到的不一致,但是如Scaled = True,则如果控件有Align属性,则界面会
  混乱,本控件就是为了解决Scaled = True的时候有Align属性的控件的界面混乱问题的。

    附:发现Delphi的一个问题:Scaled=False,PixelsPerInch=120DPI,AutoScroll=True,
  窗体控件的Align<>[alLeft,alTop],则在同一DPI下窗体在设计期和运行期不一样,本
  组件可以解决该问题。

* 开发平台:PWin98SE + Delphi 5.0
* 兼容测试:PWin9X/2000/XP + Delphi 5/6
* 本 地 化:该单元中的字符串均符合本地化处理方式
* 单元标识:$Id$
* 修改记录:
*           2004.11.19 V1.6
*                增加了属性修正当设置Form.Constrains之后,在窗口左上角缩小窗体到
*                  Constrains的最小值之后,会移动窗体位置的BUG(!!!使用了Hook!!!)
*           2004.11.19 V1.5
*                为防止更换了字体,MultiPPI函数不再使用TextHeight计算
*                保存设计期的Width和Height
*                如果有设计期的信息,则可以比较精确的计算出Constraints的大小
*                修正因后设置Constraints而引起的可能窗体变化的情形
*           2004.11.18 V1.4
*                监控动态在窗体创建的控件,并提供方法更新这些控件的大小
*           2004.11.18 V1.3
*                需要改变宽或高时通过重复设定宽或高来防止Delphi自动调整另一个属性
*           2004.11.18 V1.2
*                增强了设计期保存属性的能力,修正一些计算上的小误差
*           2004.11.18 V1.1
*                修正一些BUG
*           2003.06.20 V1.0
*                创建单元
================================================================================
|
} interface {$I CnPack.inc} uses Windows, Messages, SysUtils, Classes, Controls, Math, Forms, CnConsts, CnClasses, CnCompConsts; type TCnFormScaler = class(TCnComponent) private { Private declarations } FActive: Boolean; FScaled: Boolean; FDesignPPI: Integer; FScrollForm: Boolean; FDesignClientHeight: Integer; FDesignClientWidth: Integer; FDesignHeight: Integer; FDesignWidth: Integer; FTextHeight: Integer; FControlList: TList; FOldWndProc: TWndMethod; FFixFormConstrainsResizeBUG: Boolean; FForm: TForm; function GetDesignClientHeight: Integer; function GetDesignClientWidth: Integer; function GetDesignHeight: Integer; function GetDesignWidth: Integer; function GetDesignPPI: Integer; function GetTextHeight: Integer; procedure SetDesignPPI(const Value: Integer); procedure SetDesignClientHeight(const Value: Integer); procedure SetDesignClientWidth(const Value: Integer); procedure SetDesignHeight(const Value: Integer); procedure SetDesignWidth(const Value: Integer); procedure SetTextHeight(const Value: Integer); procedure SetActive(const Value: boolean); procedure ReadDesignPPI(Reader: TReader); procedure ReadDesignClientHeight(Reader: TReader); procedure ReadDesignClientWidth(Reader: TReader); procedure ReadDesignHeight(Reader: TReader); procedure ReadDesignWidth(Reader: TReader); procedure ReadTextHeight(Reader: TReader); procedure WriteDesignPPI(Writer: TWriter); procedure WriteDesignClientHeight(Writer: TWriter); procedure WriteDesignClientWidth(Writer: TWriter); procedure WriteDesignHeight(Writer: TWriter); procedure WriteDesignWidth(Writer: TWriter); procedure WriteTextHeight(Writer: TWriter); procedure DealWMWindowPosChanging(var Message: TMessage); procedure FormWndProc(var Message: TMessage); procedure HookFormWndProc; procedure UnHookFormWndProc; procedure SetFixFormConstrainsResizeBUG(const Value: Boolean); protected { Protected declarations } procedure DefineProperties(Filer: TFiler); override; procedure Loaded; override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure GetComponentInfo(var AName, Author, Email, Comment: string); override; public { Public declarations } class function ScreenWorkRect: TRect; class function CaptionHeight(const bSmall: Boolean = False): Integer; class function NoClientHeight(f: TForm): Integer; class function BorderWidth(f: TForm): Integer; class procedure UpdateAnchorRules(f: TForm); constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetDesignTextHeight(frm: TForm): Integer; function MultiPPI(const i: Integer; f: TForm): Integer; procedure DoEffects; procedure ScaleDynamicControls; published { Published declarations } property Active: Boolean read FActive write SetActive default True; property DesignPPI: Integer read GetDesignPPI write SetDesignPPI; property DesignClientHeight: Integer read GetDesignClientHeight write SetDesignClientHeight; property DesignClientWidth: Integer read GetDesignClientWidth write SetDesignClientWidth; property DesignHeight: Integer read GetDesignHeight write SetDesignHeight; property DesignWidth: Integer read GetDesignWidth write SetDesignWidth; property TextHeight: Integer read GetTextHeight write SetTextHeight; property Scaled: Boolean read FScaled; property ScrollForm: Boolean read FScrollForm write FScrollForm default True; property FixFormConstrainsResizeBUG: Boolean read FFixFormConstrainsResizeBUG write SetFixFormConstrainsResizeBUG default False; end; implementation { TCnFormScaler } class function TCnFormScaler.ScreenWorkRect: TRect; begin //Get work area {$IFDEF VCL_DOTNET} SystemParametersInfo(SPI_GETWORKAREA, 0, Result, 0); {$ELSE} SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0); {$ENDIF} end; class function TCnFormScaler.CaptionHeight(const bSmall: Boolean = False): Integer; begin if bSmall then Result := GetSystemMetrics(SM_CYSMCAPTION) else Result := GetSystemMetrics(SM_CYCAPTION); end; (* var ncm: NONCLIENTMETRICS; begin ncm.cbSize := SizeOf(NONCLIENTMETRICS); {$IFDEF DELPHI8} SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), ncm, 0); {$ELSE} SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), @ncm, 0); {$ENDIF} if bSmall then Result := ncm.iSmCaptionHeight else Result := ncm.iCaptionHeight; if bIncludeBorder then Result := Result + ncm.iBorderWidth * 2; end; *) class function TCnFormScaler.NoClientHeight(f: TForm): Integer; begin if Assigned(f) then Result := (f.Height - f.ClientHeight) else Result := CaptionHeight; end; class function TCnFormScaler.BorderWidth(f: TForm): Integer; begin if Assigned(f) then Result := (f.Width - f.ClientWidth) div 2 else Result := GetSystemMetrics(SM_CXFRAME); end; class procedure TCnFormScaler.UpdateAnchorRules(f: TForm); procedure DoWithControl(c: TControl); var OldAnchors: TAnchors; i: Integer; begin with c do begin for i := 0 to c.ComponentCount - 1 do if c.Components[i] is TControl then DoWithControl(TControl(c.Components[i])); //c.SetBounds(c.Left,c.Top,c.Width,c.Height); OldAnchors := Anchors; Anchors := []; Anchors := [akLeft, akTop, akRight, akBottom]; Anchors := OldAnchors; end; end; var i: Integer; //OldAnchors: TAnchors; begin //Update all FAnchorRules if Assigned(f) then begin for i := 0 to f.ControlCount - 1 do DoWithControl(f.Controls[i]); { //应该无需对窗体本身进行处理 OldAnchors := f.Anchors; f.Anchors := []; f.Anchors := [akLeft, akTop, akRight, akBottom]; f.Anchors := OldAnchors; } end; end; function TCnFormScaler.GetDesignTextHeight(frm: TForm): Integer; var NewTH: Integer; begin //Get Design-time TextHeight if not Assigned(frm) then frm := FForm; NewTH := frm.Canvas.TextHeight('0'); Result := MulDiv(NewTH, FDesignPPI, frm.PixelsPerInch); end; function TCnFormScaler.MultiPPI(const i: Integer; f: TForm): Integer; begin //Calc New Size if not Assigned(f) then f := FForm; //GetDesignTextHeight本身就是计算出来的结果,所以这么计算不因字体原因而影响 Result := MulDiv(i, f.Canvas.TextHeight('0'), GetDesignTextHeight(f)); { //分类处理虽然计算的快些,但是可能会不够精确 if f = Owner then //使用TextHeight不能正确处理字体变化过的情形 //Result := MulDiv(i, FForm.Canvas.TextHeight('0'), TextHeight) Result := MulDiv(i, f.PixelsPerInch, FDesignPPI) else //Result := MulDiv(i, f.PixelsPerInch, FDesignPPI); //GetDesignTextHeight本身就是计算出来的结果,所以这么计算不因字体原因而影响 Result := MulDiv(i, f.Canvas.TextHeight('0'), GetDesignTextHeight(f)); } end; constructor TCnFormScaler.Create(AOwner: TComponent); begin //Must on TForm. TFrame not support yet. {$IFDEF DEBUGMSG} OutputDebugString('Create'); {$ENDIF} if not (AOwner is TForm) then raise Exception.Create('Owner must inherited from TForm.'); inherited; FForm := TForm(Owner); FActive := True; FDesignClientHeight := 0; FDesignClientWidth := 0; FDesignHeight := 0; FDesignWidth := 0; FDesignPPI := 96; FTextHeight := 12; FScaled := False; FScrollForm := True; FFixFormConstrainsResizeBUG := False; FOldWndProc := nil; FControlList := TList.Create; end; destructor TCnFormScaler.Destroy; begin UnHookFormWndProc; FControlList.Free; inherited; end; procedure TCnFormScaler.Loaded; begin //Inplace OnCreate {$IFDEF DEBUGMSG} OutputDebugString('Loaded'); {$ENDIF} inherited Loaded; if csDesigning in ComponentState then begin { //设计期获取这些值没有什么意义 FDesignPPI := FForm.PixelsPerInch; FDesignClientWidth := FForm.ClientWidth; FDesignClientHeight := FForm.ClientHeight; FDesignWidth := FForm.Width; FDesignHeight := FForm.Height; FTextHeight := FForm.TextHeight; } end else DoEffects; //HookFormWndProc; end; procedure TCnFormScaler.DoEffects; var PriorHeight, PriorWidth, iCaptionHeight: Integer; WorkRect: TRect; begin //Change size {$IFDEF DEBUGMSG} OutputDebugString('DoEffects'); {$ENDIF} if (csDesigning in ComponentState) or (not FActive) or FScaled or (not Assigned(FForm)) then Exit; WorkRect := ScreenWorkRect; with FForm do try DisableAlign; {$IFDEF DEBUGMSG} OutputDebugString('DisableAlign'); {$ENDIF} if AutoScroll and (FDesignClientHeight <> 0) and (FDesignClientWidth <> 0) and (FDesignHeight <> 0) and (FDesignWidth <> 0) then begin iCaptionHeight := NoClientHeight(FForm); //iCaptionHeight := CaptionHeight(BorderStyle in [bsToolWindow, bsSizeToolWin]) + Self.BorderWidth(FForm) * 2; { MessageBox(0, PChar( IntToStr(FDesignClientWidth) + ',' + IntToStr(MultiPPI(FDesignClientWidth, FForm)) + ',' + IntToStr(MultiPPI(FDesignClientWidth, FForm) + Self.BorderWidth(FForm) * 2) + #13#10 + IntToStr(FDesignClientHeight) + ',' + IntToStr(MultiPPI(FDesignClientHeight, FForm)) + ',' + IntToStr(MultiPPI(FDesignClientHeight, FForm) + iCaptionHeight)// + #13#10 + ), '', 0); } if Scaled then begin Constraints.MinHeight := Min(MultiPPI(Constraints.MinHeight - (Self.DesignHeight - Self.DesignClientHeight), FForm) + iCaptionHeight, WorkRect.Bottom); Constraints.MinWidth := Min(MultiPPI(Constraints.MinWidth - (Self.DesignWidth - Self.DesignClientWidth), FForm) + Self.BorderWidth(FForm) * 2, WorkRect.Right); Constraints.MaxHeight := Min(MultiPPI(Constraints.MaxHeight - (Self.DesignHeight - Self.DesignClientHeight), FForm) + iCaptionHeight, WorkRect.Bottom); Constraints.MaxWidth := Min(MultiPPI(Constraints.MaxWidth - (Self.DesignWidth - Self.DesignClientWidth), FForm) + Self.BorderWidth(FForm) * 2, WorkRect.Right); ClientWidth := Min(MultiPPI(FDesignClientWidth, FForm), WorkRect.Right); ClientHeight := Min(MultiPPI(FDesignClientHeight, FForm), WorkRect.Bottom - iCaptionHeight); //Delphi会自己调整ClientWidth的大小[因为需要Scaled的时,Width变化的时候会引起Height的变化] ClientWidth := Min(MultiPPI(FDesignClientWidth, FForm), WorkRect.Right); //Width := Min(MultiPPI(FDesignClientWidth, FForm) + Self.BorderWidth(FForm) * 2, WorkRect.Right); //Height := Min(MultiPPI(FDesignClientHeight, FForm) + iCaptionHeight, WorkRect.Bottom - iCaptionHeight); end else begin Constraints.MinHeight := Min(Constraints.MinHeight - (Self.DesignHeight - Self.DesignClientHeight) + iCaptionHeight, WorkRect.Bottom); Constraints.MinWidth := Min(Constraints.MinWidth - (Self.DesignWidth - Self.DesignClientWidth) + Self.BorderWidth(FForm) * 2, WorkRect.Right); Constraints.MaxHeight := Min(Constraints.MaxHeight - (Self.DesignHeight - Self.DesignClientHeight) + iCaptionHeight, WorkRect.Bottom); Constraints.MaxWidth := Min(Constraints.MaxWidth - (Self.DesignWidth - Self.DesignClientWidth) + Self.BorderWidth(FForm) * 2, WorkRect.Right); ClientWidth := Min(FDesignClientWidth, WorkRect.Right); ClientHeight := Min(FDesignClientHeight, WorkRect.Bottom - iCaptionHeight); ClientWidth := Min(FDesignClientWidth, WorkRect.Right); end; end else if Scaled and (BorderStyle in [bsSizeable, bsSizeToolWin]) and AutoScroll then begin Constraints.MinHeight := Min(MultiPPI(Constraints.MinHeight, FForm), WorkRect.Bottom); Constraints.MinWidth := Min(MultiPPI(Constraints.MinWidth, FForm), WorkRect.Right); Constraints.MaxHeight := Min(MultiPPI(Constraints.MaxHeight, FForm), WorkRect.Bottom); Constraints.MaxWidth := Min(MultiPPI(Constraints.MaxWidth, FForm), WorkRect.Right); PriorHeight := Height; PriorWidth := Width; Width := Min(MultiPPI(PriorWidth, FForm), WorkRect.Right); Height := Min(MultiPPI(PriorHeight, FForm), WorkRect.Bottom); Width := Min(MultiPPI(PriorWidth, FForm), WorkRect.Right); end else begin Constraints.MinHeight := Min(Constraints.MinHeight, WorkRect.Bottom); Constraints.MinWidth := Min(Constraints.MinWidth, WorkRect.Right); Constraints.MaxHeight := Min(Constraints.MaxHeight, WorkRect.Bottom); Constraints.MaxWidth := Min(Constraints.MaxWidth, WorkRect.Right); PriorHeight := Height; PriorWidth := Width; Width := Min(PriorWidth, WorkRect.Right); Height := Min(PriorHeight, WorkRect.Bottom); Width := Min(PriorWidth, WorkRect.Right); end; if ScrollForm and (not (BorderStyle in [bsSizeable, bsSizeToolWin])) and (not AutoScroll) then AutoScroll := True; finally UpdateAnchorRules(FForm); EnableAlign; {$IFDEF DEBUGMSG} OutputDebugString('EnableAlign'); {$ENDIF} FScaled := True; end; //end try and with end; procedure TCnFormScaler.SetActive(const Value: boolean); begin //when stored property Active is False, maybe cannot make it. FActive := Value; {$IFDEF DEBUGMSG} if Value then OutputDebugString('SetActive: True') else OutputDebugString('SetActive: False'); {$ENDIF} if (csLoading in ComponentState) then Exit; DoEffects; end; procedure TCnFormScaler.SetDesignPPI(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetDesignPPI' + IntToStr(Value))); {$ENDIF} FDesignPPI := Value; end; end; procedure TCnFormScaler.SetDesignClientHeight(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetDesignClientHeight' + IntToStr(Value))); {$ENDIF} FDesignClientHeight := Value; end; end; procedure TCnFormScaler.SetDesignClientWidth(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetDesignClientWidth' + IntToStr(Value))); {$ENDIF} FDesignClientWidth := Value; end; end; procedure TCnFormScaler.SetDesignHeight(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetDesignHeight' + IntToStr(Value))); {$ENDIF} FDesignHeight := Value; end; end; procedure TCnFormScaler.SetDesignWidth(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetDesignWidth' + IntToStr(Value))); {$ENDIF} FDesignWidth := Value; end; end; procedure TCnFormScaler.DefineProperties(Filer: TFiler); begin inherited; Filer.DefineProperty('DesignPPI', ReadDesignPPI, WriteDesignPPI, True); Filer.DefineProperty('DesignClientHeight', ReadDesignClientHeight, WriteDesignClientHeight, True); Filer.DefineProperty('DesignClientWidth', ReadDesignClientWidth, WriteDesignClientWidth, True); Filer.DefineProperty('DesignHeight', ReadDesignHeight, WriteDesignHeight, True); Filer.DefineProperty('DesignWidth', ReadDesignWidth, WriteDesignWidth, True); Filer.DefineProperty('TextHeight', ReadTextHeight, WriteTextHeight, True); end; function TCnFormScaler.GetDesignClientHeight: Integer; begin if csDesigning in ComponentState then Result := FForm.ClientHeight else Result := FDesignClientHeight; end; function TCnFormScaler.GetDesignClientWidth: Integer; begin if csDesigning in ComponentState then Result := FForm.ClientWidth else Result := FDesignClientWidth; end; function TCnFormScaler.GetDesignHeight: Integer; begin if csDesigning in ComponentState then Result := FForm.Height else Result := FDesignHeight; end; function TCnFormScaler.GetDesignWidth: Integer; begin if csDesigning in ComponentState then Result := FForm.Width else Result := FDesignWidth; end; function TCnFormScaler.GetDesignPPI: Integer; begin if csDesigning in ComponentState then Result := FForm.PixelsPerInch else Result := FDesignPPI; end; procedure TCnFormScaler.WriteDesignClientHeight(Writer: TWriter); begin Writer.WriteInteger(GetDesignClientHeight); end; procedure TCnFormScaler.WriteDesignClientWidth(Writer: TWriter); begin Writer.WriteInteger(GetDesignClientWidth); end; procedure TCnFormScaler.WriteDesignHeight(Writer: TWriter); begin Writer.WriteInteger(GetDesignHeight); end; procedure TCnFormScaler.WriteDesignWidth(Writer: TWriter); begin Writer.WriteInteger(GetDesignWidth); end; procedure TCnFormScaler.WriteDesignPPI(Writer: TWriter); begin Writer.WriteInteger(GetDesignPPI); end; procedure TCnFormScaler.ReadDesignClientHeight(Reader: TReader); begin FDesignClientHeight := Reader.ReadInteger; end; procedure TCnFormScaler.ReadDesignClientWidth(Reader: TReader); begin FDesignClientWidth := Reader.ReadInteger; end; procedure TCnFormScaler.ReadDesignHeight(Reader: TReader); begin FDesignHeight := Reader.ReadInteger; end; procedure TCnFormScaler.ReadDesignWidth(Reader: TReader); begin FDesignWidth := Reader.ReadInteger; end; procedure TCnFormScaler.ReadDesignPPI(Reader: TReader); begin FDesignPPI := Reader.ReadInteger; end; function TCnFormScaler.GetTextHeight: Integer; begin if csDesigning in ComponentState then Result := FForm.Canvas.TextHeight('0') else Result := FTextHeight; end; procedure TCnFormScaler.ReadTextHeight(Reader: TReader); begin FTextHeight := Reader.ReadInteger; end; procedure TCnFormScaler.SetTextHeight(const Value: Integer); begin if csLoading in ComponentState then begin {$IFDEF DEBUGMSG} OutputDebugString(PChar('SetTextHeight' + IntToStr(Value))); {$ENDIF} FTextHeight := Value; end; end; procedure TCnFormScaler.WriteTextHeight(Writer: TWriter); begin Writer.WriteInteger(FForm.Canvas.TextHeight('0')); end; procedure TCnFormScaler.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if csReading in ComponentState then Exit; if Active and FForm.Scaled and (Operation = opInsert) then begin if AComponent is TControl then FControlList.Add(AComponent); end; end; type THackControl = class(TControl); procedure TCnFormScaler.ScaleDynamicControls; var i: Integer; ctrl: TControl; begin if not Active then Exit; for i := FControlList.Count - 1 downto 0 do begin if Assigned(FControlList.Items[i]) then begin ctrl := TControl(FControlList.Items[i]); if (ctrl is TCustomForm) or (ctrl is TCustomFrame) then begin //Do not scale form or frame end else if ctrl is TWinControl then begin with TWinControl(ctrl) do begin ScaleBy(FForm.Canvas.TextHeight('0'), GetDesignTextHeight(FForm)); //不够精确 //ScaleBy(FForm.PixelsPerInch, DesignPPI); //防止字体发生了变化 //ScaleBy(FForm.Canvas.TextHeight('0'), TextHeight); Left := MultiPPI(Left, nil); Top := MultiPPI(Top, nil); end; end else with THackControl(ctrl) do begin ChangeScale(FForm.Canvas.TextHeight('0'), GetDesignTextHeight(FForm)); //不够精确 //ChangeScale(FForm.PixelsPerInch, DesignPPI); //防止字体发生了变化 //ChangeScale(FForm.Canvas.TextHeight('0'), TextHeight); Left := MultiPPI(Left, nil); Top := MultiPPI(Top, nil); end; FControlList.Delete(i); end; end; end; procedure TCnFormScaler.FormWndProc(var Message: TMessage); begin if (Message.Msg = WM_WindowPosChanging) and FFixFormConstrainsResizeBUG then begin DealWMWindowPosChanging(Message); end; if Assigned(FOldWndProc) then FOldWndProc(Message); end; procedure TCnFormScaler.HookFormWndProc; begin if not Assigned(FOldWndProc) then try FOldWndProc := FForm.WindowProc; FForm.WindowProc := FormWndProc; except Application.HandleException(Self); end; end; procedure TCnFormScaler.UnHookFormWndProc; begin if Assigned(FOldWndProc) then try FForm.WindowProc := FOldWndProc; FOldWndProc := nil; except Application.HandleException(Self); end; end; procedure TCnFormScaler.DealWMWindowPosChanging(var Message: TMessage); var aRect: TRect; Msg: TWMWindowPosChanging; begin Msg := TWMWindowPosChanging(Message); //解决调整边界大小已经到了约束值之后的BUG Windows.GetWindowRect(Msg.WindowPos.hwnd, aRect); if (Msg.WindowPos.flags and SWP_NOSIZE = 0) then begin if Msg.WindowPos.cx < FForm.Constraints.MinWidth then begin Msg.WindowPos.cx := FForm.Constraints.MinWidth; if Msg.WindowPos.x <> aRect.Left then begin Msg.WindowPos.x := aRect.Right - Msg.WindowPos.cx; end; end else if (FForm.Constraints.MaxWidth > 0) and (Msg.WindowPos.cx > FForm.Constraints.MaxWidth) then begin Msg.WindowPos.cx := FForm.Constraints.MaxWidth; if Msg.WindowPos.x <> aRect.Left then begin Msg.WindowPos.x := aRect.Right - Msg.WindowPos.cx; end; end; if Msg.WindowPos.cy < FForm.Constraints.MinHeight then begin Msg.WindowPos.cy := FForm.Constraints.MinHeight; if Msg.WindowPos.y <> aRect.Top then begin Msg.WindowPos.y := aRect.Bottom - Msg.WindowPos.cy; end; end else if (FForm.Constraints.MaxHeight > 0) and (Msg.WindowPos.cy > FForm.Constraints.MaxHeight) then begin Msg.WindowPos.cy := FForm.Constraints.MaxHeight; if Msg.WindowPos.y <> aRect.Top then begin Msg.WindowPos.y := aRect.Bottom - Msg.WindowPos.cy; end; end; end; end; procedure TCnFormScaler.SetFixFormConstrainsResizeBUG( const Value: Boolean); begin FFixFormConstrainsResizeBUG := Value; if Value then HookFormWndProc else UnHookFormWndProc; end; procedure TCnFormScaler.GetComponentInfo(var AName, Author, Email, Comment: string); begin AName := SCnFormScalerName; Author := SCnPack_Shenloqi; Email := SCnPack_ShenloqiEmail; Comment := SCnFormScalerComment; end; end.