看了一下 VCL 的 Source,发现应该从 TButton 继承更方便,TBitBtn 的 CNDrawItem 消息
处理中把 Brush.color 都写死了。下面参考了 balaschen 和 Tbitbtn 的代码:
unit Button1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons;
type
TButton1 = class(TButton)
private
FColor: TColor;
FCanvas: TCanvas;
IsFocused: Boolean;
procedure SetColor(Value: TColor);
procedure DrawItem(const DrawItemStruct: TDrawItemStruct);
procedure CNMeasureItem(var Message: TWMMeasureItem); message CN_MEASUREITEM;
procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
procedure DrawButtonText(Canvas: TCanvas; const Caption: string;
TextBounds: TRect; State: TButtonState);
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure SetButtonStyle(ADefault: Boolean); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
published
property Color: TColor read FColor write SetColor default clBtnFace;
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TButton1]);
end;
{ TButton1 }
procedure TButton1.CMEnabledChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
procedure TButton1.CMFontChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
procedure TButton1.CNDrawItem(var Message: TWMDrawItem);
begin
DrawItem(Message.DrawItemStruct^);
end;
procedure TButton1.CNMeasureItem(var Message: TWMMeasureItem);
begin
with Message.MeasureItemStruct^ do
begin
itemWidth := Width;
itemHeight := Height;
end;
end;
constructor TButton1.Create(AOwner: TComponent);
begin
inherited;
FCanvas := TCanvas.Create;
FColor := clBtnFace;
end;
procedure TButton1.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
Params.Style := Params.Style or BS_OWNERDRAW;
end;
destructor TButton1.Destroy;
begin
FCanvas.Free;
inherited;
end;
procedure TButton1.DrawButtonText(Canvas: TCanvas; const Caption: string;
TextBounds: TRect; State: TButtonState);
begin
with Canvas do
begin
Brush.Style := bsClear;
if State = bsDisabled then
begin
OffsetRect(TextBounds, 1, 1);
Font.Color := clWhite;
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds, 0);
OffsetRect(TextBounds, -1, -1);
Font.Color := clDkGray;
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds, 0);
end else
DrawText(Handle, PChar(Caption), Length(Caption), TextBounds,
DT_CENTER or DT_VCENTER or DT_SINGLELINE);
end;
end;
procedure TButton1.DrawItem(const DrawItemStruct: TDrawItemStruct);
var
IsDown, IsDefault: Boolean;
State: TButtonState;
R: TRect;
begin
FCanvas.Handle := DrawItemStruct.hDC;
R := ClientRect;
with DrawItemStruct do
begin
IsDown := itemState and ODS_SELECTED <> 0;
IsDefault := itemState and ODS_FOCUS <> 0;
if not Enabled then State := bsDisabled
else if IsDown then State := bsDown
else State := bsUp;
end;
if IsFocused or IsDefault then
begin
FCanvas.Pen.Color := clWindowFrame;
FCanvas.Pen.Width := 1;
FCanvas.Brush.Style := bsClear;
FCanvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
InflateRect(R, -1, -1);
end;
if IsDown then
begin
FCanvas.Pen.Color := clBtnShadow;
FCanvas.Pen.Width := 1;
FCanvas.Brush.Color := FColor;
FCanvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
InflateRect(R, -1, -1);
end
else
with FCanvas do
begin
DrawEdge(Handle, R, BDR_RAISEDINNER or BDR_RAISEDOUTER, BF_RECT or BF_ADJUST);
FCanvas.Pen.Color := FColor;
FCanvas.Pen.Width := 1;
FCanvas.Brush.Color := FColor;
FCanvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
InflateRect(R, -1, -1);
end;
if IsFocused then
begin
R := ClientRect;
InflateRect(R, -1, -1);
end;
FCanvas.Font := Self.Font;
if IsDown then
OffsetRect(R, 1, 1);
DrawButtonText(FCanvas, Caption, R, State);
if IsFocused then
begin
R := ClientRect;
InflateRect(R, -4, -4);
FCanvas.Pen.Color := clWindowFrame;
FCanvas.Brush.Color := FColor;
DrawFocusRect(FCanvas.Handle, R);
end;
FCanvas.Handle := 0;
end;
procedure TButton1.SetButtonStyle(ADefault: Boolean);
begin
if ADefault <> IsFocused then
begin
IsFocused := ADefault;
Refresh;
end;
end;
procedure TButton1.SetColor(Value: TColor);
begin
if FColor <> Value then
begin
FColor := Value;
Invalidate;
end;
end;
end.
基本是 copy TBitbtn 的源码。