В книгах Калверта, Свана и других авторов можно найти похожий текст. Смысл
текста – "Изменить цвет кнопок Button, BitBtn нельзя, т.к. их рисует WINDOWS".
Если нельзя, но ОЧЕНЬ НУЖНО, то можно.
Небольшой компонент ColorBtn, дает возможность использовать в кнопках цвет.
Кроме того, представлено новое свойство - Frame3D, позволяющее получить более
реалистичный вид нажатой кнопки. В отличие от API, при изменении значения
свойства Frame3D, не требуется переоткрытие компонента.
Примечание. Кнопку по-прежнему рисует WINDOWS, а раскрашивает ее ColorBtn.
Код компонента на 90% повторяет код BitBtn, ничего необычного здесь нет. Чаще
заглядывайте в VCL - можно найти много интересного. На рисунке представлены
ColorButton и ColorBitBtn.
unit colorbtn;
interfaceuses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons;
type
TColorBtn = class(TButton)
private
FCanvas: TCanvas;
IsFocused: Boolean;
F3DFrame: boolean;
FButtonColor: TColor;
procedure Set3DFrame(Value: boolean);
procedure SetButtonColor(Value: TColor);
procedure CNDrawItem(varMessage: TWMDrawItem); message CN_DRAWITEM;
procedure WMLButtonDblClk(varMessage: TWMLButtonDblClk); message
WM_LBUTTONDBLCLK;
procedure DrawButtonText(const Caption: string; TRC: TRect; State:
TButtonState; BiDiFlags: Longint);
procedure CalcuateTextPosition(const Caption: string; var TRC: TRect;
BiDiFlags: Longint);
protectedprocedure CreateParams(var Params: TCreateParams); override;
procedure SetButtonStyle(ADefault: Boolean); override;
publicconstructor Create(AOwner: TComponent); override;
destructor Destroy; override;
publishedproperty ButtonColor: TColor read FButtonColor write SetButtonColor default
clBtnFace;
property Frame3D: boolean read F3DFrame write Set3DFrame default False;
end;
procedureRegister;
implementation{ TColorBtn }constructor TColorBtn.Create(AOwner: TComponent);
begininherited Create(AOwner);
Height := 21;
FCanvas := TCanvas.Create;
FButtonColor := clBtnFace;
F3DFrame := False;
end;
destructor TColorBtn.Destroy;
begin
FCanvas.Free;
inherited Destroy;
end;
procedure TColorBtn.CreateParams(var Params: TCreateParams);
begininherited CreateParams(Params);
with Params do
Style := Style or BS_OWNERDRAW;
end;
procedure TColorBtn.Set3DFrame(Value: boolean);
beginif F3DFrame <> Value then
F3DFrame := Value;
end;
procedure TColorBtn.SetButtonColor(Value: TColor);
beginif FButtonColor <> Value thenbegin
FButtonColor := Value;
Invalidate;
end;
end;
procedure TColorBtn.WMLButtonDblClk(varMessage: TWMLButtonDblClk);
begin
Perform(WM_LBUTTONDOWN, Message.Keys, Longint(Message.Pos));
end;
procedure TColorBtn.SetButtonStyle(ADefault: Boolean);
beginif IsFocused <> ADefault then
IsFocused := ADefault;
end;
procedure TColorBtn.CNDrawItem(varMessage: TWMDrawItem);
var
RC: TRect;
Flags: Longint;
State: TButtonState;
IsDown, IsDefault: Boolean;
DrawItemStruct: TDrawItemStruct;
begin
DrawItemStruct := Message.DrawItemStruct^;
FCanvas.Handle := DrawItemStruct.HDC;
RC := ClientRect;
with DrawItemStruct dobegin
IsDown := ItemState and ODS_SELECTED <> 0;
IsDefault := ItemState and ODS_FOCUS <> 0;
ifnot Enabled then
State := bsDisabled
elseif IsDown then
State := bsDown
else
State := bsUp;
end;
Flags := DFCS_BUTTONPUSH or DFCS_ADJUSTRECT;
if IsDown then
Flags := Flags or DFCS_PUSHED;
if DrawItemStruct.ItemState and ODS_DISABLED <> 0 then
Flags := Flags or DFCS_INACTIVE;
if IsFocused or IsDefault thenbegin
FCanvas.Pen.Color := clWindowFrame;
FCanvas.Pen.Width := 1;
FCanvas.Brush.Style := bsClear;
FCanvas.Rectangle(RC.Left, RC.Top, RC.Right, RC.Bottom);
InflateRect(RC, -1, -1);
end;
if IsDown thenbegin
FCanvas.Pen.Color := clBtnShadow;
FCanvas.Pen.Width := 1;
FCanvas.Rectangle(RC.Left, RC.Top, RC.Right, RC.Bottom);
InflateRect(RC, -1, -1);
if F3DFrame thenbegin
FCanvas.Pen.Color := FButtonColor;
FCanvas.Pen.Width := 1;
DrawFrameControl(DrawItemStruct.HDC, RC, DFC_BUTTON, Flags);
end;
endelse
DrawFrameControl(DrawItemStruct.HDC, RC, DFC_BUTTON, Flags);
FCanvas.Brush.Color := FButtonColor;
FCanvas.FillRect(RC);
InflateRect(RC, 1, 1);
if IsFocused thenbegin
RC := ClientRect;
InflateRect(RC, -1, -1);
end;
FCanvas.Font := Self.Font;
if IsDown then
OffsetRect(RC, 1, 1);
DrawButtonText(Caption, RC, State, 0);
if IsFocused and IsDefault thenbegin
RC := ClientRect;
InflateRect(RC, -4, -4);
FCanvas.Pen.Color := clWindowFrame;
Windows.DrawFocusRect(FCanvas.Handle, RC);
end;
FCanvas.Handle := 0;
end;
procedure TColorBtn.CalcuateTextPosition(const Caption: string; var TRC: TRect;
BiDiFlags: Integer);
var
TB: TRect;
TS, TP: TPoint;
beginwith FCanvas dobegin
TB := Rect(0, 0, TRC.Right + TRC.Left, TRC.Top + TRC.Bottom);
DrawText(Handle, PChar(Caption), Length(Caption), TB, DT_CALCRECT or
BiDiFlags);
TS := Point(TB.Right - TB.Left, TB.Bottom - TB.Top);
TP.X := ((TRC.Right - TRC.Left) - TS.X + 1) div 2;
TP.Y := ((TRC.Bottom - TRC.Top) - TS.Y + 1) div 2;
OffsetRect(TB, TP.X + TRC.Left, TP.Y + TRC.Top);
TRC := TB;
end;
end;
procedure TColorBtn.DrawButtonText(const Caption: string; TRC: TRect; State:
TButtonState; BiDiFlags: Integer);
beginwith FCanvas dobegin
CalcuateTextPosition(Caption, TRC, BiDiFlags);
Brush.Style := bsClear;
if State = bsDisabled thenbegin
OffsetRect(TRC, 1, 1);
Font.Color := clBtnHighlight;
DrawText(Handle, PChar(Caption), Length(Caption), TRC,
DT_CENTER or DT_VCENTER or BiDiFlags);
OffsetRect(TRC, -1, -1);
Font.Color := clBtnShadow;
DrawText(Handle, PChar(Caption), Length(Caption), TRC,
DT_CENTER or DT_VCENTER or BiDiFlags);
endelse
DrawText(Handle, PChar(Caption), Length(Caption), TRC,
DT_CENTER or DT_VCENTER or BiDiFlags);
end;
end;
procedureRegister;
begin
RegisterComponents('Controls', [TColorBtn]);
end;
end.
Небольшое дополнение. Кнопку по прежнему рисует WINDOWS, а раскрашивает ее
ColorBtn. Код компонента на 90% повторяет код BitBtn, ничего необычного здесь
нет. Хочется повторить слова Калверта – "Пользуйтесь исходным кодом". Чаще
заглядывайте в VCL - можно найти много интересного.
Эта часть кода - компонент TColorBtn для Delphi, который позволяет изменять цвет кнопки без прямого использования Windows API.
Компонент наследуется от TButton и имеет два свойства: ButtonColor и Frame3D, которые позволяют настроить цвет кнопки и стиль рамки соответственно. Он также переопределяет несколько методов базового класса для предоставления логики рисования.
Самый интересный момент в этом коде - метод CNDrawItem, где автор использует комбинацию функций Windows API (DrawFrameControl, DrawText) и GDI (Canvas) для рисования рамки, текста и фокусной прямоугольники кнопки. Метод также обрабатывает различные состояния (фокусировка, дефолтное, отключено) и обеспечивает поддержку 3D-рамок.
Код структурирован хорошо и легко для чтения, с четкими наименованиями переменных и комментариями, объясняющими цель каждого раздела. Однако он может улучшиться в следующих аспектах:
Усечение отступов: некоторые строки имеют несовместимые отступы, что может сделать код труднее для чтения.
Имя переменных: некоторые имена переменных слишком длинны и могут быть укорочены для лучшей читаемости.
Организация кода: логика компонента разбита на несколько методов. Могло бы быть более эффективно группировать связанные функциональности в отдельные классы или модули.
В целом, этоsolid часть кода, которая предоставляет полезную функцию для разработчиков Delphi.
Цветная кнопка: маленький компонент, позволяющий изменять цвет кнопок и получать более реалистичный вид нажатой кнопки.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.