CnFormScaler.pas 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838
  1. {******************************************************************************}
  2. { CnPack For Delphi/C++Builder }
  3. { 中国人自己的开放源码第三方开发包 }
  4. { (C)Copyright 2001-2018 CnPack 开发组 }
  5. { ------------------------------------ }
  6. { }
  7. { 本开发包是开源的自由软件,您可以遵照 CnPack 的发布协议来修 }
  8. { 改和重新发布这一程序。 }
  9. { }
  10. { 发布这一开发包的目的是希望它有用,但没有任何担保。甚至没有 }
  11. { 适合特定目的而隐含的担保。更详细的情况请参阅 CnPack 发布协议。 }
  12. { }
  13. { 您应该已经和开发包一起收到一份 CnPack 发布协议的副本。如果 }
  14. { 还没有,可访问我们的网站: }
  15. { }
  16. { 网站地址:http://www.cnpack.org }
  17. { 电子邮件:master@cnpack.org }
  18. { }
  19. {******************************************************************************}
  20. unit CnFormScaler;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:不可视工具组件包
  24. * 单元名称:在不同的屏幕DPI下,自动调整窗体的字体和大小的组件单元
  25. * 单元作者:Shenloqi, liuzhongwu
  26. * 备 注:
  27. Scaled = False并不是很好的解决不同分辨率的显示不同的方法,因为这样程序的外观
  28. 跟用户所想看到的不一致,但是如Scaled = True,则如果控件有Align属性,则界面会
  29. 混乱,本控件就是为了解决Scaled = True的时候有Align属性的控件的界面混乱问题的。
  30. 附:发现Delphi的一个问题:Scaled=False,PixelsPerInch=120DPI,AutoScroll=True,
  31. 窗体控件的Align<>[alLeft,alTop],则在同一DPI下窗体在设计期和运行期不一样,本
  32. 组件可以解决该问题。
  33. * 开发平台:PWin98SE + Delphi 5.0
  34. * 兼容测试:PWin9X/2000/XP + Delphi 5/6
  35. * 本 地 化:该单元中的字符串均符合本地化处理方式
  36. * 单元标识:$Id$
  37. * 修改记录:
  38. * 2004.11.19 V1.6
  39. * 增加了属性修正当设置Form.Constrains之后,在窗口左上角缩小窗体到
  40. * Constrains的最小值之后,会移动窗体位置的BUG(!!!使用了Hook!!!)
  41. * 2004.11.19 V1.5
  42. * 为防止更换了字体,MultiPPI函数不再使用TextHeight计算
  43. * 保存设计期的Width和Height
  44. * 如果有设计期的信息,则可以比较精确的计算出Constraints的大小
  45. * 修正因后设置Constraints而引起的可能窗体变化的情形
  46. * 2004.11.18 V1.4
  47. * 监控动态在窗体创建的控件,并提供方法更新这些控件的大小
  48. * 2004.11.18 V1.3
  49. * 需要改变宽或高时通过重复设定宽或高来防止Delphi自动调整另一个属性
  50. * 2004.11.18 V1.2
  51. * 增强了设计期保存属性的能力,修正一些计算上的小误差
  52. * 2004.11.18 V1.1
  53. * 修正一些BUG
  54. * 2003.06.20 V1.0
  55. * 创建单元
  56. ================================================================================
  57. |</PRE>}
  58. interface
  59. {$I CnPack.inc}
  60. uses
  61. Windows, Messages, SysUtils, Classes, Controls, Math, Forms,
  62. CnConsts, CnClasses, CnCompConsts;
  63. type
  64. TCnFormScaler = class(TCnComponent)
  65. private
  66. { Private declarations }
  67. FActive: Boolean;
  68. FScaled: Boolean;
  69. FDesignPPI: Integer;
  70. FScrollForm: Boolean;
  71. FDesignClientHeight: Integer;
  72. FDesignClientWidth: Integer;
  73. FDesignHeight: Integer;
  74. FDesignWidth: Integer;
  75. FTextHeight: Integer;
  76. FControlList: TList;
  77. FOldWndProc: TWndMethod;
  78. FFixFormConstrainsResizeBUG: Boolean;
  79. FForm: TForm;
  80. function GetDesignClientHeight: Integer;
  81. function GetDesignClientWidth: Integer;
  82. function GetDesignHeight: Integer;
  83. function GetDesignWidth: Integer;
  84. function GetDesignPPI: Integer;
  85. function GetTextHeight: Integer;
  86. procedure SetDesignPPI(const Value: Integer);
  87. procedure SetDesignClientHeight(const Value: Integer);
  88. procedure SetDesignClientWidth(const Value: Integer);
  89. procedure SetDesignHeight(const Value: Integer);
  90. procedure SetDesignWidth(const Value: Integer);
  91. procedure SetTextHeight(const Value: Integer);
  92. procedure SetActive(const Value: boolean);
  93. procedure ReadDesignPPI(Reader: TReader);
  94. procedure ReadDesignClientHeight(Reader: TReader);
  95. procedure ReadDesignClientWidth(Reader: TReader);
  96. procedure ReadDesignHeight(Reader: TReader);
  97. procedure ReadDesignWidth(Reader: TReader);
  98. procedure ReadTextHeight(Reader: TReader);
  99. procedure WriteDesignPPI(Writer: TWriter);
  100. procedure WriteDesignClientHeight(Writer: TWriter);
  101. procedure WriteDesignClientWidth(Writer: TWriter);
  102. procedure WriteDesignHeight(Writer: TWriter);
  103. procedure WriteDesignWidth(Writer: TWriter);
  104. procedure WriteTextHeight(Writer: TWriter);
  105. procedure DealWMWindowPosChanging(var Message: TMessage);
  106. procedure FormWndProc(var Message: TMessage);
  107. procedure HookFormWndProc;
  108. procedure UnHookFormWndProc;
  109. procedure SetFixFormConstrainsResizeBUG(const Value: Boolean);
  110. protected
  111. { Protected declarations }
  112. procedure DefineProperties(Filer: TFiler); override;
  113. procedure Loaded; override;
  114. procedure Notification(AComponent: TComponent;
  115. Operation: TOperation); override;
  116. procedure GetComponentInfo(var AName, Author, Email, Comment: string); override;
  117. public
  118. { Public declarations }
  119. class function ScreenWorkRect: TRect;
  120. class function CaptionHeight(const bSmall: Boolean = False): Integer;
  121. class function NoClientHeight(f: TForm): Integer;
  122. class function BorderWidth(f: TForm): Integer;
  123. class procedure UpdateAnchorRules(f: TForm);
  124. constructor Create(AOwner: TComponent); override;
  125. destructor Destroy; override;
  126. function GetDesignTextHeight(frm: TForm): Integer;
  127. function MultiPPI(const i: Integer; f: TForm): Integer;
  128. procedure DoEffects;
  129. procedure ScaleDynamicControls;
  130. published
  131. { Published declarations }
  132. property Active: Boolean read FActive write SetActive default True;
  133. property DesignPPI: Integer read GetDesignPPI write SetDesignPPI;
  134. property DesignClientHeight: Integer read GetDesignClientHeight write SetDesignClientHeight;
  135. property DesignClientWidth: Integer read GetDesignClientWidth write SetDesignClientWidth;
  136. property DesignHeight: Integer read GetDesignHeight write SetDesignHeight;
  137. property DesignWidth: Integer read GetDesignWidth write SetDesignWidth;
  138. property TextHeight: Integer read GetTextHeight write SetTextHeight;
  139. property Scaled: Boolean read FScaled;
  140. property ScrollForm: Boolean read FScrollForm write FScrollForm default True;
  141. property FixFormConstrainsResizeBUG: Boolean
  142. read FFixFormConstrainsResizeBUG
  143. write SetFixFormConstrainsResizeBUG
  144. default False;
  145. end;
  146. implementation
  147. { TCnFormScaler }
  148. class function TCnFormScaler.ScreenWorkRect: TRect;
  149. begin
  150. //Get work area
  151. {$IFDEF VCL_DOTNET}
  152. SystemParametersInfo(SPI_GETWORKAREA, 0, Result, 0);
  153. {$ELSE}
  154. SystemParametersInfo(SPI_GETWORKAREA, 0, @Result, 0);
  155. {$ENDIF}
  156. end;
  157. class function TCnFormScaler.CaptionHeight(const bSmall: Boolean = False): Integer;
  158. begin
  159. if bSmall then
  160. Result := GetSystemMetrics(SM_CYSMCAPTION)
  161. else
  162. Result := GetSystemMetrics(SM_CYCAPTION);
  163. end;
  164. (*
  165. var
  166. ncm: NONCLIENTMETRICS;
  167. begin
  168. ncm.cbSize := SizeOf(NONCLIENTMETRICS);
  169. {$IFDEF DELPHI8}
  170. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), ncm, 0);
  171. {$ELSE}
  172. SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(NONCLIENTMETRICS), @ncm, 0);
  173. {$ENDIF}
  174. if bSmall then
  175. Result := ncm.iSmCaptionHeight
  176. else
  177. Result := ncm.iCaptionHeight;
  178. if bIncludeBorder then
  179. Result := Result + ncm.iBorderWidth * 2;
  180. end;
  181. *)
  182. class function TCnFormScaler.NoClientHeight(f: TForm): Integer;
  183. begin
  184. if Assigned(f) then
  185. Result := (f.Height - f.ClientHeight)
  186. else
  187. Result := CaptionHeight;
  188. end;
  189. class function TCnFormScaler.BorderWidth(f: TForm): Integer;
  190. begin
  191. if Assigned(f) then
  192. Result := (f.Width - f.ClientWidth) div 2
  193. else
  194. Result := GetSystemMetrics(SM_CXFRAME);
  195. end;
  196. class procedure TCnFormScaler.UpdateAnchorRules(f: TForm);
  197. procedure DoWithControl(c: TControl);
  198. var
  199. OldAnchors: TAnchors;
  200. i: Integer;
  201. begin
  202. with c do
  203. begin
  204. for i := 0 to c.ComponentCount - 1 do
  205. if c.Components[i] is TControl then
  206. DoWithControl(TControl(c.Components[i]));
  207. //c.SetBounds(c.Left,c.Top,c.Width,c.Height);
  208. OldAnchors := Anchors;
  209. Anchors := [];
  210. Anchors := [akLeft, akTop, akRight, akBottom];
  211. Anchors := OldAnchors;
  212. end;
  213. end;
  214. var
  215. i: Integer;
  216. //OldAnchors: TAnchors;
  217. begin
  218. //Update all FAnchorRules
  219. if Assigned(f) then
  220. begin
  221. for i := 0 to f.ControlCount - 1 do
  222. DoWithControl(f.Controls[i]);
  223. { //应该无需对窗体本身进行处理
  224. OldAnchors := f.Anchors;
  225. f.Anchors := [];
  226. f.Anchors := [akLeft, akTop, akRight, akBottom];
  227. f.Anchors := OldAnchors;
  228. }
  229. end;
  230. end;
  231. function TCnFormScaler.GetDesignTextHeight(frm: TForm): Integer;
  232. var
  233. NewTH: Integer;
  234. begin
  235. //Get Design-time TextHeight
  236. if not Assigned(frm) then
  237. frm := FForm;
  238. NewTH := frm.Canvas.TextHeight('0');
  239. Result := MulDiv(NewTH, FDesignPPI, frm.PixelsPerInch);
  240. end;
  241. function TCnFormScaler.MultiPPI(const i: Integer; f: TForm): Integer;
  242. begin
  243. //Calc New Size
  244. if not Assigned(f) then
  245. f := FForm;
  246. //GetDesignTextHeight本身就是计算出来的结果,所以这么计算不因字体原因而影响
  247. Result := MulDiv(i, f.Canvas.TextHeight('0'), GetDesignTextHeight(f));
  248. { //分类处理虽然计算的快些,但是可能会不够精确
  249. if f = Owner then
  250. //使用TextHeight不能正确处理字体变化过的情形
  251. //Result := MulDiv(i, FForm.Canvas.TextHeight('0'), TextHeight)
  252. Result := MulDiv(i, f.PixelsPerInch, FDesignPPI)
  253. else
  254. //Result := MulDiv(i, f.PixelsPerInch, FDesignPPI);
  255. //GetDesignTextHeight本身就是计算出来的结果,所以这么计算不因字体原因而影响
  256. Result := MulDiv(i, f.Canvas.TextHeight('0'), GetDesignTextHeight(f));
  257. }
  258. end;
  259. constructor TCnFormScaler.Create(AOwner: TComponent);
  260. begin
  261. //Must on TForm. TFrame not support yet.
  262. {$IFDEF DEBUGMSG}
  263. OutputDebugString('Create');
  264. {$ENDIF}
  265. if not (AOwner is TForm) then
  266. raise Exception.Create('Owner must inherited from TForm.');
  267. inherited;
  268. FForm := TForm(Owner);
  269. FActive := True;
  270. FDesignClientHeight := 0;
  271. FDesignClientWidth := 0;
  272. FDesignHeight := 0;
  273. FDesignWidth := 0;
  274. FDesignPPI := 96;
  275. FTextHeight := 12;
  276. FScaled := False;
  277. FScrollForm := True;
  278. FFixFormConstrainsResizeBUG := False;
  279. FOldWndProc := nil;
  280. FControlList := TList.Create;
  281. end;
  282. destructor TCnFormScaler.Destroy;
  283. begin
  284. UnHookFormWndProc;
  285. FControlList.Free;
  286. inherited;
  287. end;
  288. procedure TCnFormScaler.Loaded;
  289. begin
  290. //Inplace OnCreate
  291. {$IFDEF DEBUGMSG}
  292. OutputDebugString('Loaded');
  293. {$ENDIF}
  294. inherited Loaded;
  295. if csDesigning in ComponentState then
  296. begin
  297. { //设计期获取这些值没有什么意义
  298. FDesignPPI := FForm.PixelsPerInch;
  299. FDesignClientWidth := FForm.ClientWidth;
  300. FDesignClientHeight := FForm.ClientHeight;
  301. FDesignWidth := FForm.Width;
  302. FDesignHeight := FForm.Height;
  303. FTextHeight := FForm.TextHeight;
  304. }
  305. end
  306. else
  307. DoEffects;
  308. //HookFormWndProc;
  309. end;
  310. procedure TCnFormScaler.DoEffects;
  311. var
  312. PriorHeight, PriorWidth, iCaptionHeight: Integer;
  313. WorkRect: TRect;
  314. begin
  315. //Change size
  316. {$IFDEF DEBUGMSG}
  317. OutputDebugString('DoEffects');
  318. {$ENDIF}
  319. if (csDesigning in ComponentState) or
  320. (not FActive) or
  321. FScaled or
  322. (not Assigned(FForm)) then
  323. Exit;
  324. WorkRect := ScreenWorkRect;
  325. with FForm do
  326. try
  327. DisableAlign;
  328. {$IFDEF DEBUGMSG}
  329. OutputDebugString('DisableAlign');
  330. {$ENDIF}
  331. if AutoScroll and
  332. (FDesignClientHeight <> 0) and
  333. (FDesignClientWidth <> 0) and
  334. (FDesignHeight <> 0) and
  335. (FDesignWidth <> 0) then
  336. begin
  337. iCaptionHeight := NoClientHeight(FForm);
  338. //iCaptionHeight := CaptionHeight(BorderStyle in [bsToolWindow, bsSizeToolWin]) + Self.BorderWidth(FForm) * 2;
  339. {
  340. MessageBox(0, PChar(
  341. IntToStr(FDesignClientWidth) + ',' +
  342. IntToStr(MultiPPI(FDesignClientWidth, FForm)) + ',' +
  343. IntToStr(MultiPPI(FDesignClientWidth, FForm) + Self.BorderWidth(FForm) * 2) + #13#10 +
  344. IntToStr(FDesignClientHeight) + ',' +
  345. IntToStr(MultiPPI(FDesignClientHeight, FForm)) + ',' +
  346. IntToStr(MultiPPI(FDesignClientHeight, FForm) + iCaptionHeight)// + #13#10 +
  347. ), '', 0);
  348. }
  349. if Scaled then
  350. begin
  351. Constraints.MinHeight :=
  352. Min(MultiPPI(Constraints.MinHeight - (Self.DesignHeight - Self.DesignClientHeight), FForm) + iCaptionHeight,
  353. WorkRect.Bottom);
  354. Constraints.MinWidth :=
  355. Min(MultiPPI(Constraints.MinWidth - (Self.DesignWidth - Self.DesignClientWidth), FForm) + Self.BorderWidth(FForm) * 2,
  356. WorkRect.Right);
  357. Constraints.MaxHeight :=
  358. Min(MultiPPI(Constraints.MaxHeight - (Self.DesignHeight - Self.DesignClientHeight), FForm) + iCaptionHeight,
  359. WorkRect.Bottom);
  360. Constraints.MaxWidth :=
  361. Min(MultiPPI(Constraints.MaxWidth - (Self.DesignWidth - Self.DesignClientWidth), FForm) + Self.BorderWidth(FForm) * 2,
  362. WorkRect.Right);
  363. ClientWidth := Min(MultiPPI(FDesignClientWidth, FForm), WorkRect.Right);
  364. ClientHeight := Min(MultiPPI(FDesignClientHeight, FForm), WorkRect.Bottom - iCaptionHeight);
  365. //Delphi会自己调整ClientWidth的大小[因为需要Scaled的时,Width变化的时候会引起Height的变化]
  366. ClientWidth := Min(MultiPPI(FDesignClientWidth, FForm), WorkRect.Right);
  367. //Width := Min(MultiPPI(FDesignClientWidth, FForm) + Self.BorderWidth(FForm) * 2, WorkRect.Right);
  368. //Height := Min(MultiPPI(FDesignClientHeight, FForm) + iCaptionHeight, WorkRect.Bottom - iCaptionHeight);
  369. end
  370. else
  371. begin
  372. Constraints.MinHeight :=
  373. Min(Constraints.MinHeight - (Self.DesignHeight - Self.DesignClientHeight) + iCaptionHeight,
  374. WorkRect.Bottom);
  375. Constraints.MinWidth :=
  376. Min(Constraints.MinWidth - (Self.DesignWidth - Self.DesignClientWidth) + Self.BorderWidth(FForm) * 2,
  377. WorkRect.Right);
  378. Constraints.MaxHeight :=
  379. Min(Constraints.MaxHeight - (Self.DesignHeight - Self.DesignClientHeight) + iCaptionHeight,
  380. WorkRect.Bottom);
  381. Constraints.MaxWidth :=
  382. Min(Constraints.MaxWidth - (Self.DesignWidth - Self.DesignClientWidth) + Self.BorderWidth(FForm) * 2,
  383. WorkRect.Right);
  384. ClientWidth := Min(FDesignClientWidth, WorkRect.Right);
  385. ClientHeight := Min(FDesignClientHeight, WorkRect.Bottom - iCaptionHeight);
  386. ClientWidth := Min(FDesignClientWidth, WorkRect.Right);
  387. end;
  388. end
  389. else if Scaled and (BorderStyle in [bsSizeable, bsSizeToolWin]) and AutoScroll then
  390. begin
  391. Constraints.MinHeight :=
  392. Min(MultiPPI(Constraints.MinHeight, FForm), WorkRect.Bottom);
  393. Constraints.MinWidth :=
  394. Min(MultiPPI(Constraints.MinWidth, FForm), WorkRect.Right);
  395. Constraints.MaxHeight :=
  396. Min(MultiPPI(Constraints.MaxHeight, FForm), WorkRect.Bottom);
  397. Constraints.MaxWidth :=
  398. Min(MultiPPI(Constraints.MaxWidth, FForm), WorkRect.Right);
  399. PriorHeight := Height;
  400. PriorWidth := Width;
  401. Width := Min(MultiPPI(PriorWidth, FForm), WorkRect.Right);
  402. Height := Min(MultiPPI(PriorHeight, FForm), WorkRect.Bottom);
  403. Width := Min(MultiPPI(PriorWidth, FForm), WorkRect.Right);
  404. end
  405. else
  406. begin
  407. Constraints.MinHeight := Min(Constraints.MinHeight, WorkRect.Bottom);
  408. Constraints.MinWidth := Min(Constraints.MinWidth, WorkRect.Right);
  409. Constraints.MaxHeight := Min(Constraints.MaxHeight, WorkRect.Bottom);
  410. Constraints.MaxWidth := Min(Constraints.MaxWidth, WorkRect.Right);
  411. PriorHeight := Height;
  412. PriorWidth := Width;
  413. Width := Min(PriorWidth, WorkRect.Right);
  414. Height := Min(PriorHeight, WorkRect.Bottom);
  415. Width := Min(PriorWidth, WorkRect.Right);
  416. end;
  417. if ScrollForm and
  418. (not (BorderStyle in [bsSizeable, bsSizeToolWin])) and
  419. (not AutoScroll) then
  420. AutoScroll := True;
  421. finally
  422. UpdateAnchorRules(FForm);
  423. EnableAlign;
  424. {$IFDEF DEBUGMSG}
  425. OutputDebugString('EnableAlign');
  426. {$ENDIF}
  427. FScaled := True;
  428. end; //end try and with
  429. end;
  430. procedure TCnFormScaler.SetActive(const Value: boolean);
  431. begin
  432. //when stored property Active is False, maybe cannot make it.
  433. FActive := Value;
  434. {$IFDEF DEBUGMSG}
  435. if Value then
  436. OutputDebugString('SetActive: True')
  437. else
  438. OutputDebugString('SetActive: False');
  439. {$ENDIF}
  440. if (csLoading in ComponentState) then
  441. Exit;
  442. DoEffects;
  443. end;
  444. procedure TCnFormScaler.SetDesignPPI(const Value: Integer);
  445. begin
  446. if csLoading in ComponentState then
  447. begin
  448. {$IFDEF DEBUGMSG}
  449. OutputDebugString(PChar('SetDesignPPI' + IntToStr(Value)));
  450. {$ENDIF}
  451. FDesignPPI := Value;
  452. end;
  453. end;
  454. procedure TCnFormScaler.SetDesignClientHeight(const Value: Integer);
  455. begin
  456. if csLoading in ComponentState then
  457. begin
  458. {$IFDEF DEBUGMSG}
  459. OutputDebugString(PChar('SetDesignClientHeight' + IntToStr(Value)));
  460. {$ENDIF}
  461. FDesignClientHeight := Value;
  462. end;
  463. end;
  464. procedure TCnFormScaler.SetDesignClientWidth(const Value: Integer);
  465. begin
  466. if csLoading in ComponentState then
  467. begin
  468. {$IFDEF DEBUGMSG}
  469. OutputDebugString(PChar('SetDesignClientWidth' + IntToStr(Value)));
  470. {$ENDIF}
  471. FDesignClientWidth := Value;
  472. end;
  473. end;
  474. procedure TCnFormScaler.SetDesignHeight(const Value: Integer);
  475. begin
  476. if csLoading in ComponentState then
  477. begin
  478. {$IFDEF DEBUGMSG}
  479. OutputDebugString(PChar('SetDesignHeight' + IntToStr(Value)));
  480. {$ENDIF}
  481. FDesignHeight := Value;
  482. end;
  483. end;
  484. procedure TCnFormScaler.SetDesignWidth(const Value: Integer);
  485. begin
  486. if csLoading in ComponentState then
  487. begin
  488. {$IFDEF DEBUGMSG}
  489. OutputDebugString(PChar('SetDesignWidth' + IntToStr(Value)));
  490. {$ENDIF}
  491. FDesignWidth := Value;
  492. end;
  493. end;
  494. procedure TCnFormScaler.DefineProperties(Filer: TFiler);
  495. begin
  496. inherited;
  497. Filer.DefineProperty('DesignPPI', ReadDesignPPI, WriteDesignPPI, True);
  498. Filer.DefineProperty('DesignClientHeight', ReadDesignClientHeight, WriteDesignClientHeight, True);
  499. Filer.DefineProperty('DesignClientWidth', ReadDesignClientWidth, WriteDesignClientWidth, True);
  500. Filer.DefineProperty('DesignHeight', ReadDesignHeight, WriteDesignHeight, True);
  501. Filer.DefineProperty('DesignWidth', ReadDesignWidth, WriteDesignWidth, True);
  502. Filer.DefineProperty('TextHeight', ReadTextHeight, WriteTextHeight, True);
  503. end;
  504. function TCnFormScaler.GetDesignClientHeight: Integer;
  505. begin
  506. if csDesigning in ComponentState then
  507. Result := FForm.ClientHeight
  508. else
  509. Result := FDesignClientHeight;
  510. end;
  511. function TCnFormScaler.GetDesignClientWidth: Integer;
  512. begin
  513. if csDesigning in ComponentState then
  514. Result := FForm.ClientWidth
  515. else
  516. Result := FDesignClientWidth;
  517. end;
  518. function TCnFormScaler.GetDesignHeight: Integer;
  519. begin
  520. if csDesigning in ComponentState then
  521. Result := FForm.Height
  522. else
  523. Result := FDesignHeight;
  524. end;
  525. function TCnFormScaler.GetDesignWidth: Integer;
  526. begin
  527. if csDesigning in ComponentState then
  528. Result := FForm.Width
  529. else
  530. Result := FDesignWidth;
  531. end;
  532. function TCnFormScaler.GetDesignPPI: Integer;
  533. begin
  534. if csDesigning in ComponentState then
  535. Result := FForm.PixelsPerInch
  536. else
  537. Result := FDesignPPI;
  538. end;
  539. procedure TCnFormScaler.WriteDesignClientHeight(Writer: TWriter);
  540. begin
  541. Writer.WriteInteger(GetDesignClientHeight);
  542. end;
  543. procedure TCnFormScaler.WriteDesignClientWidth(Writer: TWriter);
  544. begin
  545. Writer.WriteInteger(GetDesignClientWidth);
  546. end;
  547. procedure TCnFormScaler.WriteDesignHeight(Writer: TWriter);
  548. begin
  549. Writer.WriteInteger(GetDesignHeight);
  550. end;
  551. procedure TCnFormScaler.WriteDesignWidth(Writer: TWriter);
  552. begin
  553. Writer.WriteInteger(GetDesignWidth);
  554. end;
  555. procedure TCnFormScaler.WriteDesignPPI(Writer: TWriter);
  556. begin
  557. Writer.WriteInteger(GetDesignPPI);
  558. end;
  559. procedure TCnFormScaler.ReadDesignClientHeight(Reader: TReader);
  560. begin
  561. FDesignClientHeight := Reader.ReadInteger;
  562. end;
  563. procedure TCnFormScaler.ReadDesignClientWidth(Reader: TReader);
  564. begin
  565. FDesignClientWidth := Reader.ReadInteger;
  566. end;
  567. procedure TCnFormScaler.ReadDesignHeight(Reader: TReader);
  568. begin
  569. FDesignHeight := Reader.ReadInteger;
  570. end;
  571. procedure TCnFormScaler.ReadDesignWidth(Reader: TReader);
  572. begin
  573. FDesignWidth := Reader.ReadInteger;
  574. end;
  575. procedure TCnFormScaler.ReadDesignPPI(Reader: TReader);
  576. begin
  577. FDesignPPI := Reader.ReadInteger;
  578. end;
  579. function TCnFormScaler.GetTextHeight: Integer;
  580. begin
  581. if csDesigning in ComponentState then
  582. Result := FForm.Canvas.TextHeight('0')
  583. else
  584. Result := FTextHeight;
  585. end;
  586. procedure TCnFormScaler.ReadTextHeight(Reader: TReader);
  587. begin
  588. FTextHeight := Reader.ReadInteger;
  589. end;
  590. procedure TCnFormScaler.SetTextHeight(const Value: Integer);
  591. begin
  592. if csLoading in ComponentState then
  593. begin
  594. {$IFDEF DEBUGMSG}
  595. OutputDebugString(PChar('SetTextHeight' + IntToStr(Value)));
  596. {$ENDIF}
  597. FTextHeight := Value;
  598. end;
  599. end;
  600. procedure TCnFormScaler.WriteTextHeight(Writer: TWriter);
  601. begin
  602. Writer.WriteInteger(FForm.Canvas.TextHeight('0'));
  603. end;
  604. procedure TCnFormScaler.Notification(AComponent: TComponent;
  605. Operation: TOperation);
  606. begin
  607. inherited;
  608. if csReading in ComponentState then
  609. Exit;
  610. if Active and FForm.Scaled and (Operation = opInsert) then
  611. begin
  612. if AComponent is TControl then
  613. FControlList.Add(AComponent);
  614. end;
  615. end;
  616. type
  617. THackControl = class(TControl);
  618. procedure TCnFormScaler.ScaleDynamicControls;
  619. var
  620. i: Integer;
  621. ctrl: TControl;
  622. begin
  623. if not Active then
  624. Exit;
  625. for i := FControlList.Count - 1 downto 0 do
  626. begin
  627. if Assigned(FControlList.Items[i]) then
  628. begin
  629. ctrl := TControl(FControlList.Items[i]);
  630. if (ctrl is TCustomForm) or (ctrl is TCustomFrame) then
  631. begin
  632. //Do not scale form or frame
  633. end
  634. else if ctrl is TWinControl then
  635. begin
  636. with TWinControl(ctrl) do
  637. begin
  638. ScaleBy(FForm.Canvas.TextHeight('0'), GetDesignTextHeight(FForm));
  639. //不够精确
  640. //ScaleBy(FForm.PixelsPerInch, DesignPPI);
  641. //防止字体发生了变化
  642. //ScaleBy(FForm.Canvas.TextHeight('0'), TextHeight);
  643. Left := MultiPPI(Left, nil);
  644. Top := MultiPPI(Top, nil);
  645. end;
  646. end
  647. else with THackControl(ctrl) do
  648. begin
  649. ChangeScale(FForm.Canvas.TextHeight('0'), GetDesignTextHeight(FForm));
  650. //不够精确
  651. //ChangeScale(FForm.PixelsPerInch, DesignPPI);
  652. //防止字体发生了变化
  653. //ChangeScale(FForm.Canvas.TextHeight('0'), TextHeight);
  654. Left := MultiPPI(Left, nil);
  655. Top := MultiPPI(Top, nil);
  656. end;
  657. FControlList.Delete(i);
  658. end;
  659. end;
  660. end;
  661. procedure TCnFormScaler.FormWndProc(var Message: TMessage);
  662. begin
  663. if (Message.Msg = WM_WindowPosChanging) and FFixFormConstrainsResizeBUG then
  664. begin
  665. DealWMWindowPosChanging(Message);
  666. end;
  667. if Assigned(FOldWndProc) then
  668. FOldWndProc(Message);
  669. end;
  670. procedure TCnFormScaler.HookFormWndProc;
  671. begin
  672. if not Assigned(FOldWndProc) then
  673. try
  674. FOldWndProc := FForm.WindowProc;
  675. FForm.WindowProc := FormWndProc;
  676. except
  677. Application.HandleException(Self);
  678. end;
  679. end;
  680. procedure TCnFormScaler.UnHookFormWndProc;
  681. begin
  682. if Assigned(FOldWndProc) then
  683. try
  684. FForm.WindowProc := FOldWndProc;
  685. FOldWndProc := nil;
  686. except
  687. Application.HandleException(Self);
  688. end;
  689. end;
  690. procedure TCnFormScaler.DealWMWindowPosChanging(var Message: TMessage);
  691. var
  692. aRect: TRect;
  693. Msg: TWMWindowPosChanging;
  694. begin
  695. Msg := TWMWindowPosChanging(Message);
  696. //解决调整边界大小已经到了约束值之后的BUG
  697. Windows.GetWindowRect(Msg.WindowPos.hwnd, aRect);
  698. if (Msg.WindowPos.flags and SWP_NOSIZE = 0) then
  699. begin
  700. if Msg.WindowPos.cx < FForm.Constraints.MinWidth then
  701. begin
  702. Msg.WindowPos.cx := FForm.Constraints.MinWidth;
  703. if Msg.WindowPos.x <> aRect.Left then
  704. begin
  705. Msg.WindowPos.x := aRect.Right - Msg.WindowPos.cx;
  706. end;
  707. end
  708. else if (FForm.Constraints.MaxWidth > 0)
  709. and (Msg.WindowPos.cx > FForm.Constraints.MaxWidth) then
  710. begin
  711. Msg.WindowPos.cx := FForm.Constraints.MaxWidth;
  712. if Msg.WindowPos.x <> aRect.Left then
  713. begin
  714. Msg.WindowPos.x := aRect.Right - Msg.WindowPos.cx;
  715. end;
  716. end;
  717. if Msg.WindowPos.cy < FForm.Constraints.MinHeight then
  718. begin
  719. Msg.WindowPos.cy := FForm.Constraints.MinHeight;
  720. if Msg.WindowPos.y <> aRect.Top then
  721. begin
  722. Msg.WindowPos.y := aRect.Bottom - Msg.WindowPos.cy;
  723. end;
  724. end
  725. else if (FForm.Constraints.MaxHeight > 0)
  726. and (Msg.WindowPos.cy > FForm.Constraints.MaxHeight) then
  727. begin
  728. Msg.WindowPos.cy := FForm.Constraints.MaxHeight;
  729. if Msg.WindowPos.y <> aRect.Top then
  730. begin
  731. Msg.WindowPos.y := aRect.Bottom - Msg.WindowPos.cy;
  732. end;
  733. end;
  734. end;
  735. end;
  736. procedure TCnFormScaler.SetFixFormConstrainsResizeBUG(
  737. const Value: Boolean);
  738. begin
  739. FFixFormConstrainsResizeBUG := Value;
  740. if Value then
  741. HookFormWndProc
  742. else
  743. UnHookFormWndProc;
  744. end;
  745. procedure TCnFormScaler.GetComponentInfo(var AName, Author, Email,
  746. Comment: string);
  747. begin
  748. AName := SCnFormScalerName;
  749. Author := SCnPack_Shenloqi;
  750. Email := SCnPack_ShenloqiEmail;
  751. Comment := SCnFormScalerComment;
  752. end;
  753. end.