CnHint.pas 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313
  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 CnHint;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:CnPack 界面组件包
  24. * 单元名称:CnHint 控件单元
  25. * 单元作者:
  26. * 备 注:部分参考自网上佚名代码
  27. * 开发平台:PWinXP + Delphi 7.0
  28. * 兼容测试:PWin9X/2000/XP + Delphi 7.0
  29. * 本 地 化:该单元中的字符串均符合本地化处理方式
  30. * 单元标识:$Id$
  31. * 修改记录:2008.01.15 V1.0
  32. * 创建单元
  33. ================================================================================
  34. |</PRE>}
  35. interface
  36. {$I CnPack.inc}
  37. uses
  38. Windows, Messages, SysUtils, Graphics, Classes, Controls, Forms, Dialogs,
  39. StdCtrls, ExtCtrls, Math;
  40. const
  41. CN_MSG_HINT_NOTIFY = WM_USER + $0357;
  42. type
  43. TCnHint = class;
  44. TVAlignment = (vtaTopJustify, vtaBottomJustify, vtaCenter);
  45. THintStyle = (hsNormal, hsBalloonHint, hsAuto);
  46. THintPosition = (hpUpLeft, hpUpRight, hpDownLeft, hpDownRight);
  47. THintBeforeEvent = procedure(AHint: TCnHint; Rect: TRect; Text: string) of object;
  48. THintOwnerDraw = procedure(AHint: TCnHint; Canvas: TCanvas; Rect: TRect; Text: string) of object;
  49. THintMeasureRect = procedure(AHint: TCnHint; var Rect: TRect; Text: string) of object;
  50. TCnHint = class(TComponent)
  51. {* 控制所有 Hint 风格的控制组件}
  52. private
  53. FAlignment: TAlignment;
  54. FBackColor: TColor;
  55. FOnBeforeHint: THintBeforeEvent;
  56. FBorderColor: TColor;
  57. FHintPosition: THintPosition;
  58. FFont: TFont;
  59. FGlyph: TBitmap;
  60. FHintStyle: THintStyle;
  61. FOnMeasureRect: THintMeasureRect;
  62. FOnOwnerDraw: THintOwnerDraw;
  63. FTitle: string;
  64. procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  65. procedure GlyphChange(Sender: TObject);
  66. procedure SetFont(const Value: TFont);
  67. procedure SetGlyph(const Value: TBitmap);
  68. protected
  69. public
  70. constructor Create(AOwner: TComponent); override;
  71. destructor Destroy; override;
  72. procedure Loaded; override;
  73. procedure UpdateHintWindowFont;
  74. published
  75. property Alignment: TAlignment read FAlignment write FAlignment default taLeftJustify;
  76. property BackColor: TColor read FBackColor write FBackColor default $F0A07D;
  77. property BorderColor: TColor read FBorderColor write FBorderColor default clWhite;
  78. property HintPosition: THintPosition read FHintPosition write FHintPosition default hpDownRight;
  79. property Font: TFont read FFont write SetFont;
  80. property Glyph: TBitmap read FGlyph write SetGlyph;
  81. property HintStyle: THintStyle read FHintStyle write FHintStyle;
  82. property Title: string read FTitle write FTitle;
  83. property OnBeforeHint: THintBeforeEvent read FOnBeforeHint write FOnBeforeHint;
  84. property OnMeasureRect: THintMeasureRect read FOnMeasureRect write FOnMeasureRect;
  85. property OnOwnerDraw: THintOwnerDraw read FOnOwnerDraw write FOnOwnerDraw;
  86. end;
  87. TCnInternalHintWindow = class(THintWindow)
  88. {* 实际用来显示的 HintWindow,不能作为组件注册到组件板上}
  89. private
  90. FTimer: TTimer;
  91. FBitmap: TBitmap;
  92. FLastActive: Cardinal;
  93. FHint: TCnHint;
  94. FHintPosition: THintPosition;
  95. FModified: Boolean;
  96. FGlyph: TBitmap;
  97. FUpdating: Boolean;
  98. FAlignment: TAlignment;
  99. FHintStyle: THintStyle;
  100. FOnCancelHint: TNotifyEvent;
  101. FFirstLineAsTitle: Boolean;
  102. procedure GlyphChange(Sender: TObject);
  103. function FindCnHint: TCnHint;
  104. function GetTextRect(ACanvas: TCanvas; Text: string; R: TRect;
  105. HAlign: TAlignment; VAlign: TVAlignment): TRect;
  106. procedure DrawHintText(Canvas: TCanvas; R: TRect; const AText: string;
  107. IsBalloonHint: Boolean);
  108. function GetHintPosition(WorkRect: TRect; AWidth, AHeight: Integer;
  109. Pos: TPoint; IsBalloonHint: Boolean): THintPosition;
  110. procedure SetPosition(const Value: THintPosition);
  111. procedure SetGlyph(const Value: TBitmap);
  112. procedure HintNotify(var message: TMessage); message CN_MSG_HINT_NOTIFY;
  113. procedure HintTimer(Sender: TObject);
  114. protected
  115. procedure Paint; override;
  116. procedure CreateParams(var Params: TCreateParams); override;
  117. procedure DoCancelHint; virtual;
  118. public
  119. constructor Create(AOwner: TComponent); override;
  120. destructor Destroy; override;
  121. procedure ActivateHint(Rect: TRect; const AHint: string); override;
  122. procedure ActivateHintFromPos(const HintPos: TPoint; const AHint: string;
  123. const ATitle: string = ''; HidePause: Integer = 0);
  124. property HintPosition: THintPosition read FHintPosition write SetPosition;
  125. property Glyph: TBitmap read FGlyph write SetGlyph;
  126. property Alignment: TAlignment read FAlignment write FAlignment;
  127. property HintStyle: THintStyle read FHintStyle write FHintStyle;
  128. property OnCancelHint: TNotifyEvent read FOnCancelHint write FOnCancelHint;
  129. end;
  130. TCnHintWindow = class(TComponent)
  131. {* 封装一 CnInternalHintWindow 的组件}
  132. private
  133. FHintWindow: TCnInternalHintWindow;
  134. FOnCancelHint: TNotifyEvent;
  135. procedure SetGlyph(const Value: TBitmap);
  136. procedure SetPosition(const Value: THintPosition);
  137. procedure SetAlignment(const Value: TAlignment);
  138. procedure SetHintStyle(const Value: THintStyle);
  139. function GetAlignment: TAlignment;
  140. function GetGlyph: TBitmap;
  141. function GetHintStyle: THintStyle;
  142. function GetHintPosition: THintPosition;
  143. protected
  144. procedure HintWindowCancelHint(Sender: TObject);
  145. public
  146. constructor Create(AOwner: TComponent); override;
  147. destructor Destroy; override;
  148. procedure ActivateHint(const AHint: string; const ATitle: string);
  149. procedure ActivateHintFromPos(const HintPos: TPoint; const AHint: string;
  150. const ATitle: string = ''; HidePause: Integer = 5000);
  151. procedure ReleaseHandle;
  152. published
  153. property HintPosition: THintPosition read GetHintPosition write SetPosition;
  154. property Glyph: TBitmap read GetGlyph write SetGlyph;
  155. property Alignment: TAlignment read GetAlignment write SetAlignment;
  156. property HintStyle: THintStyle read GetHintStyle write SetHintStyle;
  157. property OnCancelHint: TNotifyEvent read FOnCancelHint write FOnCancelHint;
  158. end;
  159. implementation
  160. var
  161. FCnHints: TList = nil;
  162. FCnHintWindows: TList = nil;
  163. // 获得 Hint 显示区的具体尺寸
  164. function GetHintRect(ACanvas: TCanvas; const Text: string;
  165. GlyphWidth, GlyphHeight: Integer; IsBalloonHint, FirstLineAsTitle: Boolean): TRect;
  166. var
  167. Lines: TStrings;
  168. I, H, W: Integer;
  169. Len: Integer;
  170. Empty: Boolean;
  171. Added: Boolean;
  172. First: Boolean;
  173. OldStyles: TFontStyles;
  174. begin
  175. Lines := TStringList.Create;
  176. try
  177. Lines.Text := Text;
  178. H := 0;
  179. W := 0;
  180. Empty := GlyphWidth <= 0;
  181. Added := False;
  182. First := True;
  183. OldStyles := ACanvas.Font.Style;
  184. for I := 0 to Lines.Count - 1 do // 挨个计算每行文字的高度与宽度
  185. begin
  186. if FirstLineAsTitle and (I = 0) then
  187. ACanvas.Font.Style := ACanvas.Font.Style + [fsBold]
  188. else
  189. ACanvas.Font.Style := OldStyles;
  190. Len := ACanvas.TextWidth(Lines[I]);
  191. if not Empty then
  192. begin
  193. if (H <= GlyphHeight) and First then
  194. begin
  195. Inc(Len, GlyphWidth + 6); // 有图片的话,宽度加图片宽度加边缘
  196. First := False;
  197. end;
  198. if not Added and (H + 10 >= GlyphHeight) then
  199. begin
  200. Added := True;
  201. Inc(H, 6);
  202. end;
  203. end;
  204. H := H + ACanvas.TextHeight(Lines[I]);
  205. if W < Len then
  206. W := Len;
  207. end;
  208. if H < GlyphHeight then
  209. H := GlyphHeight;
  210. if IsBalloonHint then // 加上把手尖角
  211. begin
  212. Inc(H, 18);
  213. Inc(W, 12);
  214. if H < 35 then
  215. H := 35;
  216. if W < 50 then
  217. W := 50;
  218. end
  219. else
  220. begin
  221. Inc(H, 8);
  222. Inc(W, 12);
  223. end;
  224. Result := Classes.Rect(0, 0, W, H);
  225. finally
  226. ACanvas.Font.Style := OldStyles;
  227. Lines.Free;
  228. end;
  229. end;
  230. function CreateRegion(Mask: TBitmap; TransparentColor: TColor): HRGN;
  231. var
  232. Dc: HDC;
  233. Rgn: HRGN;
  234. X, Y: Integer;
  235. P: TPoint;
  236. Line: Boolean;
  237. color: TColor;
  238. begin
  239. Dc := Mask.Canvas.Handle;
  240. BeginPath(Dc);
  241. for X := 0 to Mask.Width - 1 do
  242. begin
  243. Line := False;
  244. for Y := 0 to Mask.Height - 1 do
  245. begin
  246. Color := Mask.Canvas.Pixels[x, y];
  247. if Color <> TransparentColor then
  248. begin
  249. if not Line then
  250. begin
  251. Line := True;
  252. P.x := X;
  253. P.y := Y;
  254. end;
  255. end;
  256. if (Color = TransparentColor) or (Y = Mask.Height - 1) then
  257. begin
  258. if Line then
  259. begin
  260. Line := False;
  261. MoveToEx(Dc, P.x, P.y, nil);
  262. LineTo(Dc, P.x, Y);
  263. LineTo(Dc, P.x + 1, Y);
  264. LineTo(Dc, P.x + 1, P.y);
  265. CloseFigure(Dc);
  266. end;
  267. end;
  268. end;
  269. end;
  270. EndPath(Dc);
  271. Rgn := PathToRegion(Dc);
  272. Result := Rgn;
  273. end;
  274. { TCnInternalHintWindow }
  275. procedure TCnInternalHintWindow.ActivateHint(Rect: TRect; const AHint: string);
  276. begin
  277. ActivateHintFromPos(Mouse.CursorPos, AHint);
  278. end;
  279. function GetCursorHeightMargin: Integer;
  280. var
  281. IconInfo: TIconInfo;
  282. BitmapInfoSize, BitmapBitsSize, ImageSize: DWORD;
  283. Bitmap: PBitmapInfoHeader;
  284. Bits: Pointer;
  285. BytesPerScanline: Integer;
  286. {$IFDEF WIN64}
  287. function FindScanline(Source: Pointer; MaxLen: Cardinal; Value: Cardinal): Cardinal;
  288. var
  289. I: Integer;
  290. V: Byte;
  291. P: PByte;
  292. begin
  293. // Pascal Impl.
  294. Result := MaxLen;
  295. V := Byte(Value);
  296. P := PByte(Source);
  297. for I := MaxLen downto 0 do
  298. begin
  299. if P^ = V then
  300. begin
  301. Result := I;
  302. Exit;
  303. end;
  304. Inc(P);
  305. end;
  306. end;
  307. {$ELSE}
  308. function FindScanline(Source: Pointer; MaxLen: Cardinal; Value: Cardinal): Cardinal; assembler;
  309. asm // EAX EDX ECX
  310. PUSH ECX
  311. MOV ECX, EDX // MaxLen -> ECX
  312. MOV EDX, EDI
  313. MOV EDI, EAX // Source -> EDI
  314. POP EAX // Pattern -> EAX
  315. REPE SCASB
  316. MOV EAX, ECX
  317. MOV EDI, EDX
  318. end;
  319. {$ENDIF}
  320. begin
  321. Result := GetSystemMetrics(SM_CYCURSOR);
  322. if GetIconInfo(GetCursor, IconInfo) then
  323. try
  324. GetDIBSizes(IconInfo.hbmMask, BitmapInfoSize, BitmapBitsSize);
  325. Bitmap := AllocMem(DWORD(BitmapInfoSize) + BitmapBitsSize);
  326. try
  327. Bits := Pointer(DWORD(Bitmap) + BitmapInfoSize);
  328. if GetDIB(IconInfo.hbmMask, 0, Bitmap^, Bits^) and (Bitmap^.biBitCount = 1) then
  329. begin
  330. with Bitmap^do
  331. begin
  332. BytesPerScanline := ((biWidth * biBitCount + 31) and not 31) div 8;
  333. ImageSize := biWidth * BytesPerScanline;
  334. Bits := Pointer(DWORD(Bits) + BitmapBitsSize - ImageSize);
  335. Result := FindScanline(Bits, ImageSize, $FF);
  336. if (Result = 0) and (biHeight >= 2 * biWidth) then
  337. Result := FindScanline(Pointer(DWORD(Bits) - ImageSize), ImageSize, $00);
  338. Result := Result div BytesPerScanline;
  339. end;
  340. Dec(Result, IconInfo.yHotSpot);
  341. end;
  342. finally
  343. FreeMem(Bitmap, BitmapInfoSize + BitmapBitsSize);
  344. end;
  345. finally
  346. if IconInfo.hbmColor <> 0 then
  347. DeleteObject(IconInfo.hbmColor);
  348. if IconInfo.hbmMask <> 0 then
  349. DeleteObject(IconInfo.hbmMask);
  350. end;
  351. end;
  352. procedure TCnInternalHintWindow.ActivateHintFromPos(const HintPos: TPoint;
  353. const AHint: string; const ATitle: string; HidePause: Integer);
  354. var
  355. PS: array[0..2] of TPoint;
  356. H: HRGN;
  357. Pos: TPoint;
  358. R, SaveRect: TRect;
  359. Posi: THintPosition;
  360. intW, intH: Integer;
  361. AWidth, AHeight: Integer;
  362. Rgn: HRGN;
  363. cR, cG, cB: Byte;
  364. Rect: TRect;
  365. IsBalloonHint: Boolean;
  366. AHintStyle: THintStyle;
  367. WorkArea: TRect;
  368. PT: PPoint;
  369. I: Integer;
  370. procedure GetHintRgn;
  371. var
  372. TempR: TRect;
  373. OffY: Integer;
  374. begin
  375. R.Right := R.Right - R.Left;
  376. R.Left := 0;
  377. R.Bottom := R.Bottom - R.Top;
  378. R.Top := 0;
  379. intW := R.Right;
  380. intH := R.Bottom;
  381. Pos := HintPos;
  382. SystemParametersInfo(SPI_GETWORKAREA, 0, @TempR, 0);
  383. Posi := GetHintPosition(TempR, intW, intH, Pos, IsBalloonHint);
  384. if IsBalloonHint then
  385. begin
  386. case Posi of
  387. hpUpLeft:
  388. begin
  389. OffY := GetCursorHeightMargin;
  390. Pos.Y := Pos.Y - 6;
  391. R.Left := Pos.X - (R.Right - 5);
  392. R.Top := Pos.Y - R.Bottom - OffY;
  393. R.Right := R.Right + R.Left;
  394. R.Bottom := R.Top + R.Bottom;
  395. SaveRect := R;
  396. PS[0] := Point(R.Right - 16, R.Bottom - 1);
  397. PS[1] := Point(R.Right - 16, R.Bottom + 15);
  398. PS[2] := Point(R.Right - 16 - 17, R.Bottom - 2);
  399. Rect := Classes.Rect(R.Left, R.Top, R.Right, R.Bottom + 16);
  400. end;
  401. hpUpRight:
  402. begin
  403. OffY := GetCursorHeightMargin;
  404. Pos.Y := Pos.Y - 6;
  405. R.Left := Pos.X - 25;
  406. R.Top := Pos.Y - R.Bottom - OffY;
  407. R.Right := R.Right + R.Left;
  408. R.Bottom := R.Top + R.Bottom;
  409. SaveRect := R;
  410. PS[0] := Point(R.Left + 16, R.Bottom - 1);
  411. PS[1] := Point(R.Left + 16, R.Bottom + 16);
  412. PS[2] := Point(R.Left + 16 + 17, R.Bottom - 1);
  413. Rect := Classes.Rect(R.Left, R.Top, R.Right, R.Bottom + 16);
  414. end;
  415. hpDownLeft:
  416. begin
  417. OffY := GetCursorHeightMargin + 10;
  418. R.Left := Pos.X - (R.Right - 16);
  419. R.Top := Pos.Y + OffY;
  420. R.Right := R.Right + R.Left;
  421. R.Bottom := R.Top + R.Bottom;
  422. SaveRect := R;
  423. PS[0] := Point(R.Right - 16, R.Top);
  424. PS[1] := Point(R.Right - 16, R.Top - 16);
  425. PS[2] := Point(R.Right - 16 - 17, R.Top + 1);
  426. Rect := Classes.Rect(R.Left, R.Top - 16, R.Right, R.Bottom);
  427. end;
  428. hpDownRight:
  429. begin
  430. OffY := GetCursorHeightMargin + 10;
  431. R.Left := Pos.X - 16;
  432. R.Top := Pos.Y + OffY;
  433. R.Right := R.Right + R.Left;
  434. R.Bottom := R.Top + R.Bottom;
  435. SaveRect := R;
  436. PS[0] := Point(R.Left + 16, R.Top);
  437. PS[1] := Point(R.Left + 16, R.Top - 16);
  438. PS[2] := Point(R.Left + 16 + 17, R.Top + 1);
  439. Rect := Classes.Rect(R.Left, R.Top - 16, R.Right, R.Bottom);
  440. end;
  441. end;
  442. end
  443. else
  444. begin
  445. case Posi of
  446. hpUpLeft:
  447. begin
  448. Pos.Y := Pos.Y - 15;
  449. R.Left := Pos.X - (R.Right + 10);
  450. R.Top := Pos.Y - R.Bottom - 0;
  451. R.Right := R.Right + R.Left;
  452. R.Bottom := R.Top + R.Bottom;
  453. SaveRect := R;
  454. Rect := Classes.Rect(R.Left, R.Top, R.Right, R.Bottom);
  455. end;
  456. hpUpRight:
  457. begin
  458. Pos.Y := Pos.Y - 15;
  459. R.Left := Pos.X - 10;
  460. R.Top := Pos.Y - R.Bottom - 0;
  461. R.Right := R.Right + R.Left;
  462. R.Bottom := R.Top + R.Bottom;
  463. SaveRect := R;
  464. Rect := Classes.Rect(R.Left, R.Top, R.Right, R.Bottom);
  465. end;
  466. hpDownLeft:
  467. begin
  468. OffY := GetCursorHeightMargin;
  469. Pos.Y := Pos.Y + OffY;
  470. R.Left := Pos.X - (R.Right - 0);
  471. R.Top := Pos.Y + 0;
  472. R.Right := R.Right + R.Left;
  473. R.Bottom := R.Top + R.Bottom;
  474. SaveRect := R;
  475. Rect := Classes.Rect(R.Left, R.Top, R.Right, R.Bottom);
  476. end;
  477. hpDownRight:
  478. begin
  479. OffY := GetCursorHeightMargin;
  480. Pos.Y := Pos.Y + OffY;
  481. R.Left := Pos.X - 0;
  482. R.Top := Pos.Y + 0;
  483. R.Right := R.Right + R.Left;
  484. R.Bottom := R.Top + R.Bottom;
  485. SaveRect := R;
  486. Rect := Classes.Rect(R.Left, R.Top - 0, R.Right, R.Bottom);
  487. end;
  488. end;
  489. end;
  490. end;
  491. begin
  492. if FBitmap <> nil then
  493. begin
  494. FBitmap.Width := 0;
  495. FBitmap.Height := 0;
  496. end
  497. else
  498. FBitmap := TBitmap.Create;
  499. try
  500. if FHint <> nil then
  501. if Owner <> nil then
  502. begin
  503. for I := 0 to Owner.ComponentCount - 1 do
  504. if Owner.Components[I] is TCnHint then
  505. begin
  506. FHint := Owner.Components[I] as TCnHint;
  507. Break;
  508. end;
  509. end;
  510. if FHint = nil then
  511. FHint := FindCnHint;
  512. if FHint = nil then
  513. begin
  514. AHintStyle := FHintStyle;
  515. Canvas.Font.Color := clBlack;
  516. end
  517. else
  518. begin
  519. AHintStyle := FHint.HintStyle;
  520. if FGlyph.Empty then
  521. FGlyph.Assign(FHint.FGlyph);
  522. Canvas.Font.Assign(FHint.Font);
  523. end;
  524. IsBalloonHint := (AHintStyle = hsBalloonHint) or
  525. ((AHintStyle = hsAuto) and ((ATitle <> '') or ((FHint <> nil) and (FHint.Title <> ''))));
  526. AWidth := 0;
  527. AHeight := 0;
  528. Caption := AHint;
  529. FFirstLineAsTitle := False;
  530. if ATitle <> '' then
  531. begin
  532. Caption := ATitle + #13#10 + Caption;
  533. FFirstLineAsTitle := True;
  534. end
  535. else
  536. begin
  537. if (FHint <> nil) then
  538. if FHint.Title <> '' then
  539. begin
  540. Caption := FHint.Title + #13#10 + Caption;
  541. FFirstLineAsTitle := True;
  542. end;
  543. end;
  544. // 只有显式指定了 Title、或 FHint.Title 不为空时,
  545. // 才设置 FFirstLineAsTitle 为 True; 并且 Title 的黑体效果要有图片时才能看出来
  546. if (FGlyph <> nil) and (FGlyph.Width > 0) and (FGlyph.Height > 0) then
  547. begin
  548. AWidth := FGlyph.Width;
  549. AHeight := FGlyph.Height;
  550. end;
  551. R := GetHintRect(Canvas, Caption, AWidth, AHeight, IsBalloonHint, FFirstLineAsTitle);
  552. GetHintRgn;
  553. case Posi of
  554. hpUpLeft:
  555. begin
  556. if (FHint <> nil) and (Assigned(FHint.FOnMeasureRect)) then
  557. begin
  558. FHint.FOnMeasureRect(FHint, R, Caption);
  559. OffSetRect(R, SaveRect.Right - R.Right, SaveRect.Bottom - R.Bottom);
  560. GetHintRgn;
  561. end;
  562. end;
  563. hpUpRight:
  564. begin
  565. if (FHint <> nil) and (Assigned(FHint.FOnMeasureRect)) then
  566. begin
  567. FHint.FOnMeasureRect(FHint, R, Caption);
  568. OffSetRect(R, 0, SaveRect.Bottom - R.Bottom);
  569. GetHintRgn;
  570. end;
  571. end;
  572. hpDownLeft:
  573. begin
  574. if (FHint <> nil) and (Assigned(FHint.FOnMeasureRect)) then
  575. begin
  576. FHint.FOnMeasureRect(FHint, R, Caption);
  577. OffSetRect(R, SaveRect.Right - R.Right, SaveRect.Top - R.Top);
  578. GetHintRgn;
  579. end;
  580. end;
  581. hpDownRight:
  582. begin
  583. if (FHint <> nil) and (Assigned(FHint.FOnMeasureRect)) then
  584. begin
  585. FHint.FOnMeasureRect(FHint, R, Caption);
  586. OffSetRect(R, 0, SaveRect.Top - R.Top);
  587. GetHintRgn;
  588. end;
  589. end;
  590. end;
  591. if IsBalloonHint then
  592. begin
  593. PS[0].X := PS[0].X - Rect.Left;
  594. PS[0].Y := PS[0].Y - Rect.Top;
  595. PS[1].X := PS[1].X - Rect.Left;
  596. PS[1].Y := PS[1].Y - Rect.Top;
  597. PS[2].X := PS[2].X - Rect.Left;
  598. PS[2].Y := PS[2].Y - Rect.Top;
  599. end;
  600. R.Left := R.Left - Rect.Left;
  601. R.Top := R.Top - Rect.Top;
  602. R.Right := R.Right - Rect.Left;
  603. R.Bottom := R.Bottom - Rect.Top;
  604. FBitmap.Width := Rect.Right - Rect.Left;
  605. FBitmap.Height := Rect.Bottom - Rect.Top + 1;
  606. if FHint = nil then
  607. begin
  608. cR := GetRValue(ColorToRGB(clBlack)) + 1;
  609. cG := GetGValue(ColorToRGB(clBlack)) + 2;
  610. cB := GetBValue(ColorToRGB(clBlack)) + 3;
  611. FBitmap.Canvas.Brush.Color := cB shl 16 or cG shl 8 or cR;
  612. FBitmap.Canvas.FillRect(Classes.Rect(0, 0, FBitmap.Width, FBitmap.Height));
  613. FBitmap.Canvas.Brush.Color := clInfoBk;
  614. FBitmap.Canvas.Pen.Color := clBlack;
  615. end
  616. else
  617. begin
  618. cR := GetRValue(ColorToRGB(FHint.BorderColor)) + 1;
  619. cG := GetGValue(ColorToRGB(FHint.BorderColor)) + 2;
  620. cB := GetBValue(ColorToRGB(FHint.BorderColor)) + 3;
  621. FBitmap.Canvas.Brush.Color := cB shl 16 or cG shl 8 or cR;
  622. FBitmap.Canvas.FillRect(Classes.Rect(0, 0, FBitmap.Width, FBitmap.Height));
  623. FBitmap.Canvas.Brush.Color := FHint.BackColor;
  624. FBitmap.Canvas.Pen.Color := FHint.BorderColor;
  625. end;
  626. if IsBalloonHint then
  627. begin
  628. FBitmap.Canvas.RoundRect(R.Left, R.Top, R.Right, R.Bottom, 15, 20);
  629. H := CreatePolygonRgn(PS, 3, WINDING);
  630. FillRgn(FBitmap.Canvas.Handle, H, FBitmap.Canvas.Brush.Handle);
  631. DeleteObject(H);
  632. FBitmap.Canvas.MoveTo(PS[0].X, PS[0].Y);
  633. FBitmap.Canvas.LineTo(PS[1].X, PS[1].Y);
  634. FBitmap.Canvas.LineTo(PS[2].X, PS[2].Y);
  635. end
  636. else
  637. begin
  638. FBitmap.Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  639. FBitmap.Canvas.Pen.Color := RGB(212, 208, 200);
  640. FBitmap.Canvas.MoveTo(R.Left, R.Bottom - 1);
  641. FBitmap.Canvas.LineTo(R.Left, R.Top);
  642. FBitmap.Canvas.LineTo(R.Right - 1, R.Top);
  643. end;
  644. FBitmap.Canvas.Brush.Style := bsClear;
  645. FBitmap.Canvas.Font.Assign(Canvas.Font);
  646. if (FHint <> nil) and Assigned(FHint.FOnBeforeHint) then
  647. FHint.FOnBeforeHint(FHint, R, Caption);
  648. if (FHint <> nil) and Assigned(FHint.FOnOwnerDraw) then
  649. FHint.FOnOwnerDraw(FHint, FBitmap.Canvas, R, Caption)
  650. else
  651. DrawHintText(FBitmap.Canvas, R, Caption, IsBalloonHint);
  652. if IsBalloonHint then
  653. Rgn := CreateRegion(FBitmap, FBitmap.Canvas.Pixels[0, 0])
  654. else
  655. Rgn := CreateRegion(FBitmap, FBitmap.Canvas.Pixels[0, 0] - 1);
  656. SetWindowRgn(Handle, Rgn, True);
  657. SystemParametersInfo(SPI_GETWORKAREA, 0, @WorkArea, 0);
  658. if Rect.Left < WorkArea.Left then
  659. OffsetRect(Rect, WorkArea.Left - Rect.Left, 0);
  660. if Rect.Top < WorkArea.Top then
  661. OffsetRect(Rect, 0, WorkArea.Top - Rect.Top);
  662. if Rect.Right > WorkArea.Right then
  663. OffsetRect(Rect, WorkArea.Right - Rect.Right, 0);
  664. if Rect.Bottom > WorkArea.Bottom then
  665. OffsetRect(Rect, 0, WorkArea.Bottom - Rect.Bottom);
  666. FTimer.Enabled := False;
  667. SetWindowPos(Handle, HWND_TOPMOST, Rect.Left, Rect.Top,
  668. Rect.Right - Rect.Left, Rect.Bottom - Rect.Top, SWP_NOACTIVATE);
  669. ShowWindow(Handle, SW_SHOWNOACTIVATE);
  670. Invalidate;
  671. if HidePause = 0 then
  672. HidePause := Application.HintHidePause;
  673. if HidePause > 0 then
  674. begin
  675. FTimer.Interval := HidePause;
  676. FTimer.Enabled := True;
  677. New(PT);
  678. PT^ := HintPos;
  679. PostMessage(Handle, CN_MSG_HINT_NOTIFY, HidePause, Integer(PT));
  680. end;
  681. finally
  682. FLastActive := GetTickCount;
  683. end;
  684. end;
  685. constructor TCnInternalHintWindow.Create(AOwner: TComponent);
  686. begin
  687. inherited Create(AOwner);
  688. ControlStyle := ControlStyle - [csOpaque];
  689. with Canvas do
  690. begin
  691. Brush.Style := bsClear;
  692. end;
  693. FModified := False;
  694. FGlyph := TBitmap.Create;
  695. FGlyph.OnChange := GlyphChange;
  696. FTimer := TTimer.Create(Self);
  697. FTimer.Interval := Application.HintHidePause;
  698. FTimer.OnTimer := HintTimer;
  699. FTimer.Enabled := False;
  700. FAlignment := taLeftJustify;
  701. FHintStyle := hsAuto;
  702. if FCnHintWindows = nil then
  703. FCnHintWindows := TList.Create;
  704. FCnHintWindows.Add(Self);
  705. end;
  706. procedure TCnInternalHintWindow.CreateParams(var Params: TCreateParams);
  707. begin
  708. inherited CreateParams(Params);
  709. with Params do
  710. begin
  711. Style := Style - WS_BORDER;
  712. WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  713. end;
  714. end;
  715. destructor TCnInternalHintWindow.Destroy;
  716. begin
  717. Hide;
  718. FTimer.Free;
  719. if FCnHintWindows <> nil then
  720. FCnHintWindows.Remove(Self);
  721. if FBitmap <> nil then
  722. FBitmap.Free;
  723. FGlyph.OnChange := nil;
  724. FGlyph.Free;
  725. inherited;
  726. end;
  727. procedure TCnInternalHintWindow.DrawHintText(Canvas: TCanvas; R: TRect;
  728. const AText: string; IsBalloonHint: Boolean);
  729. var
  730. I, T, L: Integer;
  731. ARect, tR: TRect;
  732. Lines: TStringList;
  733. Align: TAlignment;
  734. Empty: Boolean;
  735. Index: Integer;
  736. TopText: string;
  737. Delta: Integer;
  738. OldStyles: TFontStyles;
  739. begin
  740. if FHint <> nil then
  741. Align := FHint.Alignment
  742. else
  743. Align := FAlignment;
  744. ARect := R;
  745. InflateRect(ARect, -6, 0);
  746. T := 0;
  747. Lines := TStringList.Create;
  748. try
  749. R := ARect;
  750. Lines.Text := AText;
  751. Empty := (FGlyph = nil) or (FGlyph.Width <= 0) or (FGlyph.Height <= 0);
  752. if not Empty then
  753. begin
  754. L := 6 + FGlyph.Width;
  755. Canvas.Draw(R.Left, R.Top + 6, FGlyph);
  756. if not IsBalloonHint then
  757. Delta := 5
  758. else
  759. Delta := 10;
  760. T := Delta;
  761. Index := -1;
  762. TopText := '';
  763. for I := 0 to Lines.Count - 1 do
  764. begin
  765. TopText := TopText + Lines[I] + #13#10;
  766. if (T >= FGlyph.Height) then // T 记录文字累计的高度
  767. begin
  768. Index := I - 1;
  769. Delete(TopText, Length(TopText) - 1, 2);
  770. Inc(T, Canvas.TextHeight(Lines[I]));
  771. Break;
  772. end;
  773. Inc(T, Canvas.TextHeight(Lines[I]));
  774. end;
  775. if Index = -1 then
  776. Index := Lines.Count - 1;
  777. tR := GetTextRect(Canvas, TopText, Rect(R.Left + L, R.Top + Delta, R.Right, R.Top + T), Align, vtaTopJustify);
  778. T := 0;
  779. OldStyles := Canvas.Font.Style;
  780. for I := 0 to Index do // 画图片旁边的文字
  781. begin
  782. if FFirstLineAsTitle and (I = 0) then // 有图片、并且第一行是黑体时,画黑体字
  783. Canvas.Font.Style := Canvas.Font.Style + [fsBold]
  784. else
  785. Canvas.Font.Style := OldStyles;
  786. case Align of
  787. taLeftJustify:
  788. Canvas.TextRect(R, tR.Left, tR.Top + T, Lines[I]);
  789. taCenter:
  790. begin
  791. Canvas.TextRect(R, tR.Left + (tR.Right - tR.Left - Canvas.TextWidth(Lines[I])) div 2, tR.Top + T, Lines[I]);
  792. end;
  793. taRightJustify:
  794. begin
  795. Canvas.TextRect(R, tR.Right - Canvas.TextWidth(Lines[I]), tR.Top + T, Lines[I]);
  796. end;
  797. end;
  798. Inc(T, Canvas.TextHeight(Lines[I]));
  799. end;
  800. Canvas.Font.Style := OldStyles; // 确保恢复旧字体
  801. Inc(T, 6);
  802. L := 0;
  803. TopText := '';
  804. for I := Index + 1 to Lines.Count - 1 do
  805. TopText := TopText + Lines[I] + #13#10;
  806. Delete(TopText, Length(TopText) - 1, 2);
  807. tR := GetTextRect(Canvas, TopText, Rect(R.Left + L, R.Top + T + 6, R.Right, R.Bottom), Align, vtaTopJustify);
  808. T := 0;
  809. for I := Index + 1 to Lines.Count - 1 do // 画图片下面的文字
  810. begin
  811. case Align of
  812. taLeftJustify:
  813. Canvas.TextRect(R, tR.Left, tR.Top + T, Lines[I]);
  814. taCenter:
  815. begin
  816. Canvas.TextRect(R, tR.Left + (tR.Right - tR.Left - Canvas.TextWidth(Lines[I])) div 2, tR.Top + T, Lines[I]);
  817. end;
  818. taRightJustify:
  819. begin
  820. Canvas.TextRect(R, tR.Right - Canvas.TextWidth(Lines[I]), tR.Top + T, Lines[I]);
  821. end;
  822. end;
  823. Inc(T, Canvas.TextHeight(Lines[I]));
  824. end;
  825. end
  826. else // 无图片,不画黑体的 Title,按平常画
  827. begin
  828. tR := GetTextRect(Canvas, Lines.Text, R, Align, vtaCenter);
  829. for I := 0 to Lines.Count - 1 do
  830. begin
  831. case Align of
  832. taLeftJustify:
  833. Canvas.TextRect(R, tR.Left, tR.Top + T, Lines[I]);
  834. taCenter:
  835. begin
  836. Canvas.TextRect(R, tR.Left + (tR.Right - tR.Left - Canvas.TextWidth(Lines[I])) div 2, tR.Top + T, Lines[I]);
  837. end;
  838. taRightJustify:
  839. begin
  840. Canvas.TextRect(R, tR.Right - Canvas.TextWidth(Lines[I]), tR.Top + T, Lines[I]);
  841. end;
  842. end;
  843. Inc(T, Canvas.TextHeight(Lines[I]));
  844. end;
  845. end;
  846. finally
  847. Lines.Free;
  848. end;
  849. end;
  850. function TCnInternalHintWindow.FindCnHint: TCnHint;
  851. begin
  852. Result := nil;
  853. if FCnHints <> nil then
  854. if FCnHints.Count > 0 then
  855. Result := TCnHint(FCnHints[0]);
  856. end;
  857. function TCnInternalHintWindow.GetHintPosition(WorkRect: TRect; AWidth, AHeight:
  858. Integer; Pos: TPoint; IsBalloonHint: Boolean): THintPosition;
  859. var
  860. R: TRect;
  861. B: Boolean;
  862. Delta: Integer;
  863. begin
  864. R := WorkRect;
  865. InflateRect(R, -10, -10);
  866. B := False;
  867. if IsBalloonHint then
  868. Delta := 16
  869. else
  870. Delta := 0;
  871. if not FModified and (FHint <> nil) then
  872. Result := FHint.HintPosition
  873. else
  874. Result := FHintPosition;
  875. case Result of
  876. hpUpLeft:
  877. B := ((AHeight + Delta - (Pos.Y - R.Top)) < 0) and ((AWidth - Delta) <= (Pos.X - R.Left));
  878. hpUpRight:
  879. B := ((AHeight + Delta - (Pos.Y - R.Top)) < 0) and ((AWidth - Delta + Pos.X) < R.Right);
  880. hpDownLeft:
  881. B := ((AHeight + Delta - (R.Bottom - Pos.Y)) < 0) and ((AWidth - Delta) <= (Pos.X - R.Left));
  882. hpDownRight:
  883. B := ((AHeight + Delta - (R.Bottom - Pos.Y)) < 0) and ((AWidth - Delta + Pos.X) < R.Right);
  884. end;
  885. if B then
  886. Exit;
  887. if (AHeight + Delta - (Pos.Y - R.Top)) < 0 then
  888. begin
  889. if (AWidth - Delta + Pos.X) < R.Right then
  890. Result := hpUpRight
  891. else
  892. Result := hpUpLeft;
  893. end
  894. else
  895. begin
  896. if (AWidth - Delta + Pos.X) < R.Right then
  897. Result := hpDownRight
  898. else
  899. Result := hpDownLeft;
  900. end;
  901. end;
  902. function TCnInternalHintWindow.GetTextRect(ACanvas: TCanvas; Text: string; R: TRect;
  903. HAlign: TAlignment; VAlign: TVAlignment): TRect;
  904. var
  905. I, Len: Integer;
  906. Lines: TStrings;
  907. str: string;
  908. tR: TRect;
  909. intW, intH: Integer;
  910. OldStyles: TFontStyles;
  911. begin
  912. Result := Rect(R.Left, R.Top, R.Left, R.Top);
  913. tR := Result;
  914. Lines := TStringList.Create;
  915. try
  916. Lines.Text := Text;
  917. OldStyles := ACanvas.Font.Style;
  918. for I := 0 to Lines.Count - 1 do
  919. begin
  920. str := Lines[I];
  921. if str <> '' then
  922. begin
  923. // 首行、无图片、并且有 Title 时,才按黑体来
  924. if FFirstLineAsTitle and (I = 0) and not Glyph.Empty then
  925. begin
  926. ACanvas.Font.Style := [fsBold]
  927. end
  928. else
  929. ACanvas.Font.Style := OldStyles;
  930. Len := ACanvas.TextWidth(str);
  931. if (tR.Right - tR.Left) < Len then
  932. tR.Right := tR.Left + Len;
  933. tR.Bottom := tR.Bottom + ACanvas.TextHeight(str);
  934. end;
  935. end;
  936. intW := tR.Right - tR.Left;
  937. intH := tR.Bottom - tR.Top;
  938. case HAlign of
  939. taLeftJustify:
  940. tR.Left := R.Left;
  941. taCenter:
  942. tR.Left := R.Left + Max((R.Right - R.Left - (tR.Right - tR.Left)) div 2, 0);
  943. taRightJustify:
  944. tR.Left := R.Right - (tR.Right - tR.Left);
  945. end;
  946. case VAlign of
  947. vtaTopJustify:
  948. tR.Top := R.Top + 3;
  949. vtaBottomJustify:
  950. tR.Top := R.Bottom - (tR.Bottom - tR.Top) - 1;
  951. vtaCenter:
  952. tR.Top := R.Top + Max((R.Bottom - R.Top - (tR.Bottom - tR.Top)) div 2, 0);
  953. end;
  954. tR.Right := tR.Left + intW;
  955. tR.Bottom := tR.Top + intH;
  956. Result := tR;
  957. finally
  958. Lines.Free;
  959. ACanvas.Font.Style := OldStyles;
  960. end;
  961. end;
  962. procedure TCnInternalHintWindow.GlyphChange(Sender: TObject);
  963. begin
  964. if FUpdating then
  965. Exit;
  966. FUpdating := True;
  967. try
  968. if (FGlyph <> nil) and not Glyph.Transparent then
  969. begin
  970. Glyph.TransparentColor := Glyph.Canvas.Pixels[0, 0];
  971. Glyph.Transparent := True;
  972. end;
  973. finally
  974. FUpdating := False;
  975. end;
  976. end;
  977. procedure TCnInternalHintWindow.HintNotify(var message: TMessage);
  978. var
  979. AMsg: MSG;
  980. HintControl: TControl;
  981. P: TPoint;
  982. PT: PPoint;
  983. begin
  984. PT := PPoint(Pointer(message.LParam));
  985. P := PT^;
  986. HintControl := FindDragTarget(P, True);
  987. Dispose(PT);
  988. while (GetMessage(AMsg, 0, 0, 0)) do
  989. begin
  990. if (AMsg.message = WM_QUIT) then
  991. begin
  992. PostQuitMessage(0);
  993. Break;
  994. end
  995. else if ((AMsg.message >= WM_KEYFIRST) and (AMsg.message <= WM_KEYLAST))
  996. or ((AMsg.message = CM_ACTIVATE) or (AMsg.message = CM_DEACTIVATE)) or
  997. (AMsg.message = CM_APPKEYDOWN) or (AMsg.message = CM_APPSYSCOMMAND) or
  998. (AMsg.message = WM_COMMAND) or ((AMsg.message > WM_MOUSEMOVE) and
  999. (AMsg.message <= WM_MOUSELAST)) or (AMsg.message = WM_NCMOUSEMOVE) then
  1000. begin
  1001. PostMessage(AMsg.hwnd, AMsg.message, AMsg.wParam, AMsg.lParam);
  1002. Break;
  1003. end
  1004. else if (AMsg.message = WM_MOUSEMOVE) and (HintControl <> FindDragTarget(Mouse.CursorPos, True)) then
  1005. begin
  1006. PostMessage(AMsg.hwnd, AMsg.message, AMsg.wParam, AMsg.lParam);
  1007. Break;
  1008. end
  1009. else
  1010. begin
  1011. TranslateMessage(AMsg);
  1012. DispatchMessage(AMsg);
  1013. end;
  1014. end;
  1015. // DoCancelHint;
  1016. end;
  1017. procedure TCnInternalHintWindow.Paint;
  1018. begin
  1019. BitBlt(Canvas.Handle, 0, 0, FBitmap.Width, FBitmap.Height,
  1020. FBitmap.Canvas.Handle, 0, 0, SRCCOPY);
  1021. end;
  1022. procedure TCnInternalHintWindow.SetPosition(const Value: THintPosition);
  1023. begin
  1024. if FHintPosition <> Value then
  1025. begin
  1026. FHintPosition := Value;
  1027. FModified := True;
  1028. end;
  1029. end;
  1030. procedure TCnInternalHintWindow.SetGlyph(const Value: TBitmap);
  1031. begin
  1032. FGlyph.Assign(Value);
  1033. end;
  1034. procedure TCnInternalHintWindow.DoCancelHint;
  1035. begin
  1036. if Assigned(FOnCancelHint) then
  1037. FOnCancelHint(Self);
  1038. end;
  1039. procedure TCnInternalHintWindow.HintTimer(Sender: TObject);
  1040. begin
  1041. FTimer.Enabled := False;
  1042. DoCancelHint;
  1043. ReleaseHandle;
  1044. end;
  1045. { TCnHint }
  1046. procedure TCnHint.CMFontChanged(var Message: TMessage);
  1047. begin
  1048. inherited;
  1049. Application.ShowHint := not Application.ShowHint;
  1050. Application.ShowHint := not Application.ShowHint;
  1051. UpdateHintWindowFont;
  1052. end;
  1053. constructor TCnHint.Create(AOwner: TComponent);
  1054. begin
  1055. inherited Create(AOwner);
  1056. FBackColor := clInfoBk; //$F0A07D;
  1057. FBorderColor := clBlack;
  1058. FHintPosition := hpDownRight;
  1059. FAlignment := taLeftJustify;
  1060. FFont := TFont.Create;
  1061. FFont.Color := clBlack;
  1062. FGlyph := TBitmap.Create;
  1063. FGlyph.OnChange := GlyphChange;
  1064. if not (csDesigning in ComponentState) then
  1065. begin
  1066. HintWindowClass := TCnInternalHintWindow;
  1067. Application.ShowHint := not Application.ShowHint;
  1068. Application.ShowHint := not Application.ShowHint;
  1069. UpdateHintWindowFont;
  1070. end;
  1071. if FCnHints = nil then
  1072. FCnHints := TList.Create;
  1073. FCnHints.Add(Self);
  1074. end;
  1075. destructor TCnHint.Destroy;
  1076. begin
  1077. if FCnHints <> nil then
  1078. FCnHints.Remove(Self);
  1079. FFont.Free;
  1080. FGlyph.OnChange := nil;
  1081. FGlyph.Free;
  1082. inherited;
  1083. end;
  1084. procedure TCnHint.GlyphChange(Sender: TObject);
  1085. begin
  1086. if FGlyph <> nil then
  1087. begin
  1088. Glyph.TransparentColor := Glyph.Canvas.Pixels[0, 0];
  1089. Glyph.Transparent := True;
  1090. end;
  1091. end;
  1092. procedure TCnHint.Loaded;
  1093. begin
  1094. if not (csDesigning in ComponentState) then
  1095. begin
  1096. inherited Loaded;
  1097. HintWindowClass := TCnInternalHintWindow;
  1098. Application.ShowHint := not Application.ShowHint;
  1099. Application.ShowHint := not Application.ShowHint;
  1100. UpdateHintWindowFont;
  1101. end;
  1102. end;
  1103. procedure TCnHint.SetFont(const Value: TFont);
  1104. begin
  1105. FFont.Assign(Value);
  1106. Application.ShowHint := not Application.ShowHint;
  1107. Application.ShowHint := not Application.ShowHint;
  1108. UpdateHintWindowFont;
  1109. end;
  1110. procedure TCnHint.SetGlyph(const Value: TBitmap);
  1111. begin
  1112. FGlyph.Assign(Value);
  1113. end;
  1114. procedure TCnHint.UpdateHintWindowFont;
  1115. var
  1116. I: Integer;
  1117. begin
  1118. if FCnHintWindows <> nil then
  1119. if FCnHintWindows.Count > 0 then
  1120. for I := 0 to FCnHintWindows.Count - 1 do
  1121. if Application.Components[I] is TCnInternalHintWindow then
  1122. TCnInternalHintWindow(FCnHintWindows[I]).Canvas.Font.Assign(FFont);
  1123. end;
  1124. { TCnHintWindow }
  1125. procedure TCnHintWindow.ActivateHint(const AHint: string; const ATitle: string);
  1126. begin
  1127. FHintWindow.ActivateHintFromPos(Mouse.CursorPos, AHint, ATitle);
  1128. end;
  1129. procedure TCnHintWindow.ActivateHintFromPos(const HintPos: TPoint;
  1130. const AHint, ATitle: string; HidePause: Integer);
  1131. begin
  1132. FHintWindow.ActivateHintFromPos(HintPos, AHint, ATitle, HidePause);
  1133. end;
  1134. constructor TCnHintWindow.Create(AOwner: TComponent);
  1135. begin
  1136. inherited;
  1137. FHintWindow := TCnInternalHintWindow.Create(Self);
  1138. FHintWindow.OnCancelHint := HintWindowCancelHint;
  1139. end;
  1140. destructor TCnHintWindow.Destroy;
  1141. begin
  1142. FHintWindow.Free;
  1143. inherited;
  1144. end;
  1145. function TCnHintWindow.GetAlignment: TAlignment;
  1146. begin
  1147. Result := FHintWindow.Alignment;
  1148. end;
  1149. function TCnHintWindow.GetGlyph: TBitmap;
  1150. begin
  1151. Result := FHintWindow.Glyph;
  1152. end;
  1153. function TCnHintWindow.GetHintPosition: THintPosition;
  1154. begin
  1155. Result := FHintWindow.HintPosition;
  1156. end;
  1157. function TCnHintWindow.GetHintStyle: THintStyle;
  1158. begin
  1159. Result := FHintWindow.HintStyle;
  1160. end;
  1161. procedure TCnHintWindow.HintWindowCancelHint(Sender: TObject);
  1162. begin
  1163. if Assigned(FOnCancelHint) then
  1164. FOnCancelHint(FHintWindow);
  1165. end;
  1166. procedure TCnHintWindow.ReleaseHandle;
  1167. begin
  1168. FHintWindow.ReleaseHandle;
  1169. end;
  1170. procedure TCnHintWindow.SetAlignment(const Value: TAlignment);
  1171. begin
  1172. FHintWindow.Alignment := Value;
  1173. end;
  1174. procedure TCnHintWindow.SetGlyph(const Value: TBitmap);
  1175. begin
  1176. FHintWindow.Glyph.Assign(Value);
  1177. end;
  1178. procedure TCnHintWindow.SetHintStyle(const Value: THintStyle);
  1179. begin
  1180. FHintWindow.HintStyle := Value;
  1181. end;
  1182. procedure TCnHintWindow.SetPosition(const Value: THintPosition);
  1183. begin
  1184. FHintWindow.HintPosition := Value;
  1185. end;
  1186. initialization
  1187. finalization
  1188. FreeAndNil(FCnHints);
  1189. FreeAndNil(FCnHintWindows);
  1190. end.