CnSpin.pas 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  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 CnSpin;
  21. {* |<PRE>
  22. ================================================================================
  23. * 软件名称:界面控件包
  24. * 单元名称:CnSpin 控件单元
  25. * 单元作者:CnPack开发组
  26. * 开发平台:PWin98SE + Delphi 5.0
  27. * 兼容测试:PWin9X/2000/XP + Delphi 5/6
  28. * 本 地 化:该单元中的字符串均符合本地化处理方式
  29. * 备 注:由 周劲羽 从 Delphi 5 中移植而来,以实现 BCB 的兼容
  30. * 修改记录:2002.12.07 V1.0
  31. * 移植自 Delphi 5
  32. ================================================================================
  33. |</PRE>}
  34. interface
  35. {$I CnPack.inc}
  36. uses
  37. Windows, Classes, StdCtrls, ExtCtrls, Controls, Messages, SysUtils,
  38. Forms, Graphics, Menus, Buttons, CnConsts;
  39. const
  40. InitRepeatPause = 400; { pause before repeat timer (ms) }
  41. RepeatPause = 100; { pause before hint window displays (ms)}
  42. type
  43. TNumGlyphs = Buttons.TNumGlyphs;
  44. TCnTimerSpeedButton = class;
  45. { TCnSpinButton }
  46. TCnSpinButton = class(TWinControl)
  47. private
  48. FUpButton: TCnTimerSpeedButton;
  49. FDownButton: TCnTimerSpeedButton;
  50. FFocusedButton: TCnTimerSpeedButton;
  51. FFocusControl: TWinControl;
  52. FOnUpClick: TNotifyEvent;
  53. FOnDownClick: TNotifyEvent;
  54. function CreateButton: TCnTimerSpeedButton;
  55. function GetUpGlyph: TBitmap;
  56. function GetDownGlyph: TBitmap;
  57. procedure SetUpGlyph(Value: TBitmap);
  58. procedure SetDownGlyph(Value: TBitmap);
  59. function GetUpNumGlyphs: TNumGlyphs;
  60. function GetDownNumGlyphs: TNumGlyphs;
  61. procedure SetUpNumGlyphs(Value: TNumGlyphs);
  62. procedure SetDownNumGlyphs(Value: TNumGlyphs);
  63. procedure BtnClick(Sender: TObject);
  64. procedure BtnMouseDown(Sender: TObject; Button: TMouseButton;
  65. Shift: TShiftState; X, Y: Integer);
  66. procedure SetFocusBtn(Btn: TCnTimerSpeedButton);
  67. procedure AdjustSize(var W, H: Integer); reintroduce;
  68. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  69. procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
  70. procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  71. procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  72. protected
  73. procedure Loaded; override;
  74. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  75. procedure Notification(AComponent: TComponent;
  76. Operation: TOperation); override;
  77. public
  78. constructor Create(AOwner: TComponent); override;
  79. procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  80. published
  81. property Align;
  82. property Anchors;
  83. property Constraints;
  84. property Ctl3D;
  85. property DownGlyph: TBitmap read GetDownGlyph write SetDownGlyph;
  86. property DownNumGlyphs: TNumGlyphs read GetDownNumGlyphs write SetDownNumGlyphs default 1;
  87. property DragCursor;
  88. property DragKind;
  89. property DragMode;
  90. property Enabled;
  91. property FocusControl: TWinControl read FFocusControl write FFocusControl;
  92. property ParentCtl3D;
  93. property ParentShowHint;
  94. property PopupMenu;
  95. property ShowHint;
  96. property TabOrder;
  97. property TabStop;
  98. property UpGlyph: TBitmap read GetUpGlyph write SetUpGlyph;
  99. property UpNumGlyphs: TNumGlyphs read GetUpNumGlyphs write SetUpNumGlyphs default 1;
  100. property Visible;
  101. property OnDownClick: TNotifyEvent read FOnDownClick write FOnDownClick;
  102. property OnDragDrop;
  103. property OnDragOver;
  104. property OnEndDock;
  105. property OnEndDrag;
  106. property OnEnter;
  107. property OnExit;
  108. property OnStartDock;
  109. property OnStartDrag;
  110. property OnUpClick: TNotifyEvent read FOnUpClick write FOnUpClick;
  111. end;
  112. { TCnSpinEdit }
  113. TCnSpinEdit = class(TCustomEdit)
  114. private
  115. FMinValue: LongInt;
  116. FMaxValue: LongInt;
  117. FIncrement: LongInt;
  118. FButton: TCnSpinButton;
  119. FEditorEnabled: Boolean;
  120. function GetMinHeight: Integer;
  121. function GetValue: LongInt;
  122. function CheckValue (NewValue: LongInt): LongInt;
  123. procedure SetValue (NewValue: LongInt);
  124. procedure SetEditRect;
  125. procedure WMSize(var Message: TWMSize); message WM_SIZE;
  126. procedure CMEnter(var Message: TCMGotFocus); message CM_ENTER;
  127. procedure CMExit(var Message: TCMExit); message CM_EXIT;
  128. procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
  129. procedure WMCut(var Message: TWMCut); message WM_CUT;
  130. protected
  131. function IsValidChar(Key: Char): Boolean; virtual;
  132. procedure UpClick (Sender: TObject); virtual;
  133. procedure DownClick (Sender: TObject); virtual;
  134. procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  135. procedure KeyPress(var Key: Char); override;
  136. procedure CreateParams(var Params: TCreateParams); override;
  137. procedure CreateWnd; override;
  138. public
  139. constructor Create(AOwner: TComponent); override;
  140. destructor Destroy; override;
  141. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  142. property Button: TCnSpinButton read FButton;
  143. published
  144. property Anchors;
  145. property AutoSelect;
  146. property AutoSize;
  147. property Color;
  148. property Constraints;
  149. property Ctl3D;
  150. property DragCursor;
  151. property DragMode;
  152. property EditorEnabled: Boolean read FEditorEnabled write FEditorEnabled default True;
  153. property Enabled;
  154. property Font;
  155. property Increment: LongInt read FIncrement write FIncrement default 1;
  156. property MaxLength;
  157. property MaxValue: LongInt read FMaxValue write FMaxValue;
  158. property MinValue: LongInt read FMinValue write FMinValue;
  159. property ParentColor;
  160. property ParentCtl3D;
  161. property ParentFont;
  162. property ParentShowHint;
  163. property PopupMenu;
  164. property ReadOnly;
  165. property ShowHint;
  166. property TabOrder;
  167. property TabStop;
  168. property Value: LongInt read GetValue write SetValue;
  169. property Visible;
  170. property OnChange;
  171. property OnClick;
  172. property OnDblClick;
  173. property OnDragDrop;
  174. property OnDragOver;
  175. property OnEndDrag;
  176. property OnEnter;
  177. property OnExit;
  178. property OnKeyDown;
  179. property OnKeyPress;
  180. property OnKeyUp;
  181. property OnMouseDown;
  182. property OnMouseMove;
  183. property OnMouseUp;
  184. property OnStartDrag;
  185. end;
  186. { TTimerSpeedButton }
  187. TTimeBtnState = set of (tbFocusRect, tbAllowTimer);
  188. TCnTimerSpeedButton = class(TSpeedButton)
  189. private
  190. FRepeatTimer: TTimer;
  191. FTimeBtnState: TTimeBtnState;
  192. procedure TimerExpired(Sender: TObject);
  193. protected
  194. procedure Paint; override;
  195. procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  196. X, Y: Integer); override;
  197. procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  198. X, Y: Integer); override;
  199. public
  200. destructor Destroy; override;
  201. property TimeBtnState: TTimeBtnState read FTimeBtnState write FTimeBtnState;
  202. end;
  203. implementation
  204. {$R CNSPIN}
  205. { TCnSpinButton }
  206. constructor TCnSpinButton.Create(AOwner: TComponent);
  207. begin
  208. inherited Create(AOwner);
  209. ControlStyle := ControlStyle - [csAcceptsControls, csSetCaption] +
  210. [csFramed, csOpaque];
  211. FUpButton := CreateButton;
  212. FDownButton := CreateButton;
  213. UpGlyph := nil;
  214. DownGlyph := nil;
  215. Width := 20;
  216. Height := 25;
  217. FFocusedButton := FUpButton;
  218. end;
  219. function TCnSpinButton.CreateButton: TCnTimerSpeedButton;
  220. begin
  221. Result := TCnTimerSpeedButton.Create (Self);
  222. Result.OnClick := BtnClick;
  223. Result.OnMouseDown := BtnMouseDown;
  224. Result.Visible := True;
  225. Result.Enabled := True;
  226. Result.TimeBtnState := [tbAllowTimer];
  227. Result.Parent := Self;
  228. end;
  229. procedure TCnSpinButton.Notification(AComponent: TComponent;
  230. Operation: TOperation);
  231. begin
  232. inherited Notification(AComponent, Operation);
  233. if (Operation = opRemove) and (AComponent = FFocusControl) then
  234. FFocusControl := nil;
  235. end;
  236. procedure TCnSpinButton.AdjustSize (var W, H: Integer);
  237. begin
  238. if (FUpButton = nil) or (csLoading in ComponentState) then Exit;
  239. if W < 15 then W := 15;
  240. FUpButton.SetBounds (0, 0, W, H div 2);
  241. FDownButton.SetBounds (0, FUpButton.Height - 1, W, H - FUpButton.Height + 1);
  242. end;
  243. procedure TCnSpinButton.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  244. var
  245. W, H: Integer;
  246. begin
  247. W := AWidth;
  248. H := AHeight;
  249. AdjustSize(W, H);
  250. inherited SetBounds(ALeft, ATop, W, H);
  251. end;
  252. procedure TCnSpinButton.WMSize(var Message: TWMSize);
  253. var
  254. W, H: Integer;
  255. begin
  256. inherited;
  257. W := Width;
  258. H := Height;
  259. AdjustSize(W, H);
  260. if (W <> Width) or (H <> Height) then
  261. inherited SetBounds(Left, Top, W, H);
  262. Message.Result := 0;
  263. end;
  264. procedure TCnSpinButton.WMSetFocus(var Message: TWMSetFocus);
  265. begin
  266. FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
  267. FFocusedButton.Invalidate;
  268. end;
  269. procedure TCnSpinButton.WMKillFocus(var Message: TWMKillFocus);
  270. begin
  271. FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
  272. FFocusedButton.Invalidate;
  273. end;
  274. procedure TCnSpinButton.KeyDown(var Key: Word; Shift: TShiftState);
  275. begin
  276. case Key of
  277. VK_UP:
  278. begin
  279. SetFocusBtn(FUpButton);
  280. FUpButton.Click;
  281. end;
  282. VK_DOWN:
  283. begin
  284. SetFocusBtn(FDownButton);
  285. FDownButton.Click;
  286. end;
  287. VK_SPACE:
  288. FFocusedButton.Click;
  289. end;
  290. end;
  291. procedure TCnSpinButton.BtnMouseDown(Sender: TObject; Button: TMouseButton;
  292. Shift: TShiftState; X, Y: Integer);
  293. begin
  294. if Button = mbLeft then
  295. begin
  296. SetFocusBtn(TCnTimerSpeedButton(Sender));
  297. if (FFocusControl <> nil) and FFocusControl.TabStop and
  298. FFocusControl.CanFocus and (GetFocus <> FFocusControl.Handle) then
  299. FFocusControl.SetFocus
  300. else if TabStop and (GetFocus <> Handle) and CanFocus then
  301. SetFocus;
  302. end;
  303. end;
  304. procedure TCnSpinButton.BtnClick(Sender: TObject);
  305. begin
  306. if Sender = FUpButton then
  307. begin
  308. if Assigned(FOnUpClick) then FOnUpClick(Self);
  309. end
  310. else
  311. if Assigned(FOnDownClick) then FOnDownClick(Self);
  312. end;
  313. procedure TCnSpinButton.SetFocusBtn(Btn: TCnTimerSpeedButton);
  314. begin
  315. if TabStop and CanFocus and (Btn <> FFocusedButton) then
  316. begin
  317. FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
  318. FFocusedButton := Btn;
  319. if (GetFocus = Handle) then
  320. begin
  321. FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
  322. Invalidate;
  323. end;
  324. end;
  325. end;
  326. procedure TCnSpinButton.WMGetDlgCode(var Message: TWMGetDlgCode);
  327. begin
  328. Message.Result := DLGC_WANTARROWS;
  329. end;
  330. procedure TCnSpinButton.Loaded;
  331. var
  332. W, H: Integer;
  333. begin
  334. inherited Loaded;
  335. W := Width;
  336. H := Height;
  337. AdjustSize(W, H);
  338. if (W <> Width) or (H <> Height) then
  339. inherited SetBounds(Left, Top, W, H);
  340. end;
  341. function TCnSpinButton.GetUpGlyph: TBitmap;
  342. begin
  343. Result := FUpButton.Glyph;
  344. end;
  345. procedure TCnSpinButton.SetUpGlyph(Value: TBitmap);
  346. begin
  347. if Value <> nil then
  348. FUpButton.Glyph := Value
  349. else
  350. begin
  351. FUpButton.Glyph.Handle := LoadBitmap(HInstance, 'CNSPINEDITUP');
  352. FUpButton.NumGlyphs := 1;
  353. FUpButton.Invalidate;
  354. end;
  355. end;
  356. function TCnSpinButton.GetUpNumGlyphs: TNumGlyphs;
  357. begin
  358. Result := FUpButton.NumGlyphs;
  359. end;
  360. procedure TCnSpinButton.SetUpNumGlyphs(Value: TNumGlyphs);
  361. begin
  362. FUpButton.NumGlyphs := Value;
  363. end;
  364. function TCnSpinButton.GetDownGlyph: TBitmap;
  365. begin
  366. Result := FDownButton.Glyph;
  367. end;
  368. procedure TCnSpinButton.SetDownGlyph(Value: TBitmap);
  369. begin
  370. if Value <> nil then
  371. FDownButton.Glyph := Value
  372. else
  373. begin
  374. FDownButton.Glyph.Handle := LoadBitmap(HInstance, 'CNSPINEDITDOWN');
  375. FUpButton.NumGlyphs := 1;
  376. FDownButton.Invalidate;
  377. end;
  378. end;
  379. function TCnSpinButton.GetDownNumGlyphs: TNumGlyphs;
  380. begin
  381. Result := FDownButton.NumGlyphs;
  382. end;
  383. procedure TCnSpinButton.SetDownNumGlyphs(Value: TNumGlyphs);
  384. begin
  385. FDownButton.NumGlyphs := Value;
  386. end;
  387. { TCnSpinEdit }
  388. constructor TCnSpinEdit.Create(AOwner: TComponent);
  389. begin
  390. inherited Create(AOwner);
  391. FButton := TCnSpinButton.Create(Self);
  392. FButton.Width := 15;
  393. FButton.Height := 17;
  394. FButton.Visible := True;
  395. FButton.Parent := Self;
  396. FButton.FocusControl := Self;
  397. FButton.OnUpClick := UpClick;
  398. FButton.OnDownClick := DownClick;
  399. Text := '0';
  400. ControlStyle := ControlStyle - [csSetCaption];
  401. FIncrement := 1;
  402. FEditorEnabled := True;
  403. end;
  404. destructor TCnSpinEdit.Destroy;
  405. begin
  406. FButton := nil;
  407. inherited Destroy;
  408. end;
  409. procedure TCnSpinEdit.GetChildren(Proc: TGetChildProc; Root: TComponent);
  410. begin
  411. end;
  412. procedure TCnSpinEdit.KeyDown(var Key: Word; Shift: TShiftState);
  413. begin
  414. if Key = VK_UP then UpClick(Self)
  415. else if Key = VK_DOWN then DownClick(Self);
  416. inherited KeyDown(Key, Shift);
  417. end;
  418. procedure TCnSpinEdit.KeyPress(var Key: Char);
  419. begin
  420. if not IsValidChar(Key) then
  421. begin
  422. Key := #0;
  423. MessageBeep(0)
  424. end;
  425. if Key <> #0 then inherited KeyPress(Key);
  426. end;
  427. function TCnSpinEdit.IsValidChar(Key: Char): Boolean;
  428. begin
  429. Result := (AnsiChar(Key) in [{$IFDEF DELPHIXE3_UP}FormatSettings.{$ENDIF}DecimalSeparator, '+', '-', '0'..'9']) or
  430. ((Key < #32) and (Key <> Chr(VK_RETURN)));
  431. if not FEditorEnabled and Result and ((Key >= #32) or
  432. (Key = Char(VK_BACK)) or (Key = Char(VK_DELETE))) then
  433. Result := False;
  434. end;
  435. procedure TCnSpinEdit.CreateParams(var Params: TCreateParams);
  436. begin
  437. inherited CreateParams(Params);
  438. { Params.Style := Params.Style and not WS_BORDER; }
  439. Params.Style := Params.Style or ES_MULTILINE or WS_CLIPCHILDREN;
  440. end;
  441. procedure TCnSpinEdit.CreateWnd;
  442. begin
  443. inherited CreateWnd;
  444. SetEditRect;
  445. end;
  446. procedure TCnSpinEdit.SetEditRect;
  447. var
  448. Loc: TRect;
  449. begin
  450. SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
  451. Loc.Bottom := ClientHeight + 1; {+1 is workaround for windows paint bug}
  452. Loc.Right := ClientWidth - FButton.Width - 2;
  453. Loc.Top := 0;
  454. Loc.Left := 0;
  455. SendMessage(Handle, EM_SETRECTNP, 0, LongInt(@Loc));
  456. SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc)); {debug}
  457. end;
  458. procedure TCnSpinEdit.WMSize(var Message: TWMSize);
  459. var
  460. MinHeight: Integer;
  461. begin
  462. inherited;
  463. MinHeight := GetMinHeight;
  464. { text edit bug: if size to less than minheight, then edit ctrl does
  465. not display the text }
  466. if Height < MinHeight then
  467. Height := MinHeight
  468. else if FButton <> nil then
  469. begin
  470. if NewStyleControls and Ctl3D then
  471. FButton.SetBounds(Width - FButton.Width - 5, 0, FButton.Width, Height - 5)
  472. else FButton.SetBounds(Width - FButton.Width, 1, FButton.Width, Height - 3);
  473. SetEditRect;
  474. end;
  475. end;
  476. function TCnSpinEdit.GetMinHeight: Integer;
  477. var
  478. DC: HDC;
  479. SaveFont: HFont;
  480. I: Integer;
  481. SysMetrics, Metrics: TTextMetric;
  482. begin
  483. DC := GetDC(0);
  484. GetTextMetrics(DC, SysMetrics);
  485. SaveFont := SelectObject(DC, Font.Handle);
  486. GetTextMetrics(DC, Metrics);
  487. SelectObject(DC, SaveFont);
  488. ReleaseDC(0, DC);
  489. I := SysMetrics.tmHeight;
  490. if I > Metrics.tmHeight then I := Metrics.tmHeight;
  491. Result := Metrics.tmHeight + I div 4 + GetSystemMetrics(SM_CYBORDER) * 4 + 2;
  492. end;
  493. procedure TCnSpinEdit.UpClick(Sender: TObject);
  494. begin
  495. if ReadOnly then MessageBeep(0)
  496. else Value := Value + FIncrement;
  497. end;
  498. procedure TCnSpinEdit.DownClick(Sender: TObject);
  499. begin
  500. if ReadOnly then MessageBeep(0)
  501. else Value := Value - FIncrement;
  502. end;
  503. procedure TCnSpinEdit.WMPaste(var Message: TWMPaste);
  504. begin
  505. if not FEditorEnabled or ReadOnly then Exit;
  506. inherited;
  507. end;
  508. procedure TCnSpinEdit.WMCut(var Message: TWMPaste);
  509. begin
  510. if not FEditorEnabled or ReadOnly then Exit;
  511. inherited;
  512. end;
  513. procedure TCnSpinEdit.CMExit(var Message: TCMExit);
  514. begin
  515. inherited;
  516. if CheckValue(Value) <> Value then
  517. SetValue(Value);
  518. end;
  519. function TCnSpinEdit.GetValue: LongInt;
  520. begin
  521. Result := StrToIntDef (Text, FMinValue);
  522. end;
  523. procedure TCnSpinEdit.SetValue(NewValue: LongInt);
  524. begin
  525. Text := IntToStr(CheckValue(NewValue));
  526. end;
  527. function TCnSpinEdit.CheckValue(NewValue: LongInt): LongInt;
  528. begin
  529. Result := NewValue;
  530. if (FMaxValue <> FMinValue) then
  531. begin
  532. if NewValue < FMinValue then
  533. Result := FMinValue
  534. else if NewValue > FMaxValue then
  535. Result := FMaxValue;
  536. end;
  537. end;
  538. procedure TCnSpinEdit.CMEnter(var Message: TCMGotFocus);
  539. begin
  540. if AutoSelect and not (csLButtonDown in ControlState) then
  541. SelectAll;
  542. inherited;
  543. end;
  544. {TTimerSpeedButton}
  545. destructor TCnTimerSpeedButton.Destroy;
  546. begin
  547. if FRepeatTimer <> nil then
  548. FRepeatTimer.Free;
  549. inherited Destroy;
  550. end;
  551. procedure TCnTimerSpeedButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  552. X, Y: Integer);
  553. begin
  554. inherited MouseDown(Button, Shift, X, Y);
  555. if tbAllowTimer in FTimeBtnState then
  556. begin
  557. if FRepeatTimer = nil then
  558. FRepeatTimer := TTimer.Create(Self);
  559. FRepeatTimer.OnTimer := TimerExpired;
  560. FRepeatTimer.Interval := InitRepeatPause;
  561. FRepeatTimer.Enabled := True;
  562. end;
  563. end;
  564. procedure TCnTimerSpeedButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  565. X, Y: Integer);
  566. begin
  567. inherited MouseUp(Button, Shift, X, Y);
  568. if FRepeatTimer <> nil then
  569. FRepeatTimer.Enabled := False;
  570. end;
  571. procedure TCnTimerSpeedButton.TimerExpired(Sender: TObject);
  572. begin
  573. FRepeatTimer.Interval := RepeatPause;
  574. if (FState = bsDown) and MouseCapture then
  575. begin
  576. try
  577. Click;
  578. except
  579. FRepeatTimer.Enabled := False;
  580. raise;
  581. end;
  582. end;
  583. end;
  584. procedure TCnTimerSpeedButton.Paint;
  585. var
  586. R: TRect;
  587. begin
  588. inherited Paint;
  589. if tbFocusRect in FTimeBtnState then
  590. begin
  591. R := Bounds(0, 0, Width, Height);
  592. InflateRect(R, -3, -3);
  593. if FState = bsDown then
  594. OffsetRect(R, 1, 1);
  595. DrawFocusRect(Canvas.Handle, R);
  596. end;
  597. end;
  598. end.