📄 tflatspinbuttonunit.pas
字号:
unit TFlatSpinButtonUnit;
interface
{$I DFS.inc}
uses Windows, Classes, StdCtrls, ExtCtrls, Controls, Messages, SysUtils,
Forms, Graphics, Menus, Buttons, TFlatSpeedButtonUnit;
const
InitRepeatPause = 400; // pause before repeat timer (ms)
RepeatPause = 100; // pause before hint window displays (ms)
type
TNumGlyphs = Buttons.TNumGlyphs;
TTimerSpeedButton = class;
{ TFlatSpinButton }
TSpinButton = class(TWinControl)
private
FUpButton: TTimerSpeedButton;
FDownButton: TTimerSpeedButton;
FFocusedButton: TTimerSpeedButton;
FFocusControl: TWinControl;
FOnUpClick: TNotifyEvent;
FOnDownClick: TNotifyEvent;
function CreateButton: TTimerSpeedButton;
function GetUpGlyph: TBitmap;
function GetDownGlyph: TBitmap;
procedure SetUpGlyph (Value: TBitmap);
procedure SetDownGlyph (Value: TBitmap);
function GetUpNumGlyphs: TNumGlyphs;
function GetDownNumGlyphs: TNumGlyphs;
procedure SetUpNumGlyphs (Value: TNumGlyphs);
procedure SetDownNumGlyphs (Value: TNumGlyphs);
procedure BtnClick (Sender: TObject);
procedure BtnMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
procedure SetFocusBtn (Btn: TTimerSpeedButton);
procedure AdjustSize (var W, H: Integer); {$IFDEF DFS_COMPILER_4_UP} reintroduce; {$ENDIF}
procedure WMSize (var Message: TWMSize); message WM_SIZE;
procedure WMSetFocus (var Message: TWMSetFocus); message WM_SETFOCUS;
procedure WMKillFocus (var Message: TWMKillFocus); message WM_KILLFOCUS;
procedure WMGetDlgCode (var Message: TWMGetDlgCode); message WM_GETDLGCODE;
protected
procedure Loaded; override;
procedure KeyDown (var Key: Word; Shift: TShiftState); override;
procedure Notification (AComponent: TComponent; Operation: TOperation); override;
public
constructor Create (AOwner: TComponent); override;
procedure SetBounds (ALeft, ATop, AWidth, AHeight: Integer); override;
published
property DownGlyph: TBitmap read GetDownGlyph write SetDownGlyph;
property DownNumGlyphs: TNumGlyphs read GetDownNumGlyphs write SetDownNumGlyphs default 1;
property FocusControl: TWinControl read FFocusControl write FFocusControl;
property UpGlyph: TBitmap read GetUpGlyph write SetUpGlyph;
property UpNumGlyphs: TNumGlyphs read GetUpNumGlyphs write SetUpNumGlyphs default 1;
property Enabled;
property Visible;
property OnDownClick: TNotifyEvent read FOnDownClick write FOnDownClick;
property OnUpClick: TNotifyEvent read FOnUpClick write FOnUpClick;
end;
{ TTimerSpeedButton }
TTimeBtnState = set of (tbFocusRect, tbAllowTimer);
TTimerSpeedButton = class(TFlatSpeedButton)
private
FRepeatTimer: TTimer;
FTimeBtnState: TTimeBtnState;
procedure TimerExpired( Sender: TObject);
protected
procedure MouseDown (Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp (Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
public
destructor Destroy; override;
property TimeBtnState: TTimeBtnState read FTimeBtnState write FTimeBtnState;
end;
implementation
{$R FlatArrow}
{ TSpinButton }
constructor TSpinButton.Create (AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle - [csAcceptsControls, csSetCaption] + [csFramed, csOpaque];
FUpButton := CreateButton;
FDownButton := CreateButton;
UpGlyph := nil;
DownGlyph := nil;
Width := 21;
Height := 10;
FFocusedButton := FUpButton;
end;
function TSpinButton.CreateButton: TTimerSpeedButton;
begin
Result := TTimerSpeedButton.Create(Self);
Result.OnClick := BtnClick;
Result.OnMouseDown := BtnMouseDown;
Result.Visible := True;
Result.Enabled := True;
Result.TimeBtnState := [tbAllowTimer];
Result.Parent := Self;
end;
procedure TSpinButton.Notification (AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (AComponent = FFocusControl) then
FFocusControl := nil;
end;
procedure TSpinButton.AdjustSize (var W, H: Integer);
begin
if (FUpButton = nil) or (csLoading in ComponentState) then Exit;
FUpButton.SetBounds(0, 0, 11, H);
FDownButton.SetBounds(10, 0, 11, H);
end;
procedure TSpinButton.SetBounds (ALeft, ATop, AWidth, AHeight: Integer);
var
W, H: Integer;
begin
W := AWidth;
H := AHeight;
AdjustSize (W, H);
inherited SetBounds (ALeft, ATop, W, H);
end;
procedure TSpinButton.WMSize (var Message: TWMSize);
var
W, H: Integer;
begin
inherited;
// check for minimum size
W := Width;
H := Height;
AdjustSize (W, H);
if (W <> Width) or (H <> Height) then
inherited SetBounds(Left, Top, W, H);
Message.Result := 0;
end;
procedure TSpinButton.WMSetFocus (var Message: TWMSetFocus);
begin
FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
FFocusedButton.Invalidate;
end;
procedure TSpinButton.WMKillFocus (var Message: TWMKillFocus);
begin
FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
FFocusedButton.Invalidate;
end;
procedure TSpinButton.KeyDown (var Key: Word; Shift: TShiftState);
begin
case Key of
VK_UP:
begin
SetFocusBtn(FUpButton);
FUpButton.Click;
end;
VK_DOWN:
begin
SetFocusBtn(FDownButton);
FDownButton.Click;
end;
VK_SPACE:
FFocusedButton.Click;
end;
end;
procedure TSpinButton.BtnMouseDown (Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if Button = mbLeft then
begin
SetFocusBtn (TTimerSpeedButton (Sender));
if (FFocusControl <> nil) and FFocusControl.TabStop and
FFocusControl.CanFocus and (GetFocus <> FFocusControl.Handle) then
FFocusControl.SetFocus
else if TabStop and (GetFocus <> Handle) and CanFocus then
SetFocus;
end;
end;
procedure TSpinButton.BtnClick (Sender: TObject);
begin
if Sender = FUpButton then
if Assigned(FOnUpClick) then
FOnUpClick(Self);
if Sender = FDownButton then
if Assigned(FOnDownClick) then
FOnDownClick(Self);
end;
procedure TSpinButton.SetFocusBtn (Btn: TTimerSpeedButton);
begin
if TabStop and CanFocus and (Btn <> FFocusedButton) then
begin
FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState - [tbFocusRect];
FFocusedButton := Btn;
if (GetFocus = Handle) then
begin
FFocusedButton.TimeBtnState := FFocusedButton.TimeBtnState + [tbFocusRect];
Invalidate;
end;
end;
end;
procedure TSpinButton.WMGetDlgCode (var Message: TWMGetDlgCode);
begin
Message.Result := DLGC_WANTARROWS;
end;
procedure TSpinButton.Loaded;
var
W, H: Integer;
begin
inherited Loaded;
W := Width;
H := Height;
AdjustSize (W, H);
if (W <> Width) or (H <> Height) then
inherited SetBounds(Left, Top, Width, Height);
end;
function TSpinButton.GetUpGlyph: TBitmap;
begin
Result := FUpButton.Glyph;
end;
procedure TSpinButton.SetUpGlyph (Value: TBitmap);
begin
if Value <> nil then
FUpButton.Glyph := Value
else
begin
FUpButton.Glyph.Handle := LoadBitmap(HInstance, 'FlatUp');
FUpButton.NumGlyphs := 1;
FUpButton.Margin := 2;
FUpButton.Invalidate;
FUpButton.Layout := blGlyphTop;
end;
end;
function TSpinButton.GetUpNumGlyphs: TNumGlyphs;
begin
Result := FUpButton.NumGlyphs;
end;
procedure TSpinButton.SetUpNumGlyphs (Value: TNumGlyphs);
begin
FUpButton.NumGlyphs := Value;
end;
function TSpinButton.GetDownGlyph: TBitmap;
begin
Result := FDownButton.Glyph;
end;
procedure TSpinButton.SetDownGlyph (Value: TBitmap);
begin
if Value <> nil then
FDownButton.Glyph := Value
else
begin
FDownButton.Glyph.Handle := LoadBitmap(HInstance, 'FlatDown');
FDownButton.NumGlyphs := 1;
FDownButton.Margin := 2;
FDownButton.Invalidate;
FDownButton.Layout := blGlyphBottom;
end;
end;
function TSpinButton.GetDownNumGlyphs: TNumGlyphs;
begin
Result := FDownButton.NumGlyphs;
end;
procedure TSpinButton.SetDownNumGlyphs (Value: TNumGlyphs);
begin
FDownButton.NumGlyphs := Value;
end;
{TTimerSpeedButton}
destructor TTimerSpeedButton.Destroy;
begin
if FRepeatTimer <> nil then
FRepeatTimer.Free;
inherited Destroy;
end;
procedure TTimerSpeedButton.MouseDown (Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited MouseDown (Button, Shift, X, Y);
if tbAllowTimer in FTimeBtnState then
begin
if FRepeatTimer = nil then
FRepeatTimer := TTimer.Create(Self);
FRepeatTimer.OnTimer := TimerExpired;
FRepeatTimer.Interval := InitRepeatPause;
FRepeatTimer.Enabled := True;
end;
end;
procedure TTimerSpeedButton.MouseUp (Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
inherited MouseUp (Button, Shift, X, Y);
if FRepeatTimer <> nil then
FRepeatTimer.Enabled := False;
end;
procedure TTimerSpeedButton.TimerExpired (Sender: TObject);
begin
FRepeatTimer.Interval := RepeatPause;
if (FState = bsDown) and MouseCapture then
begin
try
Click;
except
FRepeatTimer.Enabled := False;
raise;
end;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -