Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

Видоизменяем чекбоксы в Delphi

01.01.2007

В WIN3.1 чекбоксы заполняются символом "X". В WIN95 и WINNT - символом "V". В тандартной палитре Delphi чекбоксы заполняются символом "X". Спрашивается - почему фирма Borland/Inprise не исправила значёк чекбокса для W95/W98 ?. Данный пример позволяет заполнять чекбокс такими значками как: "X", "V", "o", "закрашенным прямоугольником", или бриллиантиком.

Пример тестировался под WIN95 и WINNT.

{ 
==================================================================== 
                          Обозначения
==================================================================== 
X = крестик
V = галочка 
o = кружок 
 
+-+ 
|W| = заполненный прямоугольник 
+-+ 
 
/\ 
= бриллиантик 
\/ 
 
==================================================================== 
                  Преимущества этого чекбокса 
==================================================================== 
Вы можете найти множество чекбоксов в интернете. Но у них есть недостаток, они не обрабатывают сообщение WM_KILLFOCUS. Приведённый ниже пример делает это. 
==================================================================== 
} 
Unit CheckBoxX; 
 
Interface 
 
Uses 
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, 
  Dialogs, StdCtrls; 
 
Const 
   { другие константы } 
   fRBoxWidth  : Integer = 13; // ширина квадрата checkbox 
   fRBoxHeight : Integer = 13; // высота квадрата checkbox 
 
Type 
  TState = (cbUnchecked,cbChecked,cbGrayed); // такой же как в Delphi 
  TType = (cbCross,cbMark,cbBullet,cbDiamond,cbRect); // добавленный 
  TMouseState = (msMouseUp,msMouseDown); 
  TAlignment = (taRightJustify,taLeftJustify); // The same 
 
  TCheckBoxX = class(TCustomControl) 
 
  Private 
    { Private declarations } 
    fChecked        : Boolean; 
    fCaption        : String; 
    fColor          : TColor; 
    fState          : TState; 
    fFont            : TFont; 
    fAllowGrayed    : Boolean; 
    fFocus          : Boolean; 
    fType            : TType; 
    fMouseState     : TMouseState; 
    fAlignment      : TAlignment; 
    fTextTop        : Integer;  // отступ текта с верху 
    fTextLeft       : Integer;  // отступ текта с лева 
    fBoxTop         : Integer;  // координата чекбокса сверху 
    fBoxLeft        : Integer;  // координата чекбокса слева 
 
    Procedure fSetChecked(Bo : Boolean); 
    Procedure fSetCaption(S : String); 
    Procedure fSetColor(C : TColor); 
    Procedure fSetState(cbState : TState); 
    Procedure fSetFont(cbFont : TFont); 
    Procedure fSetAllowGrayed(Bo : Boolean); 
    Procedure fSetType(T : TType); 
    Procedure fSetAlignment(A : TAlignment); 
 
  Protected 
    { Protected declarations } 
    Procedure Paint; override; 
    Procedure MouseDown(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); override; 
    Procedure MouseUp(Button: TMouseButton; Shift: TShiftState; 
      X, Y: Integer); override; 
    Procedure WMKillFocus(var Message : TWMKillFocus); 
      Message WM_KILLFOCUS; // это убирает контур фокуса! 
    Procedure WMSetFocus(var Message : TWMSetFocus); 
      Message WM_SETFOCUS; // Если вы используете клавишу TAB или Shift-Tab 
    Procedure KeyDown(var Key : Word; Shift : TShiftState); override; 
      // перехват KeyDown 
    Procedure KeyUp(var Key : Word; Shift : TShiftState); override; 
      // перехват KeyUp 
 
  Public 
    { Public declarations } 
    // Если поместить Create и Destroy в раздел protected, 
    // то Delphi начинает ругаться. 
    Constructor Create(AOwner : TComponent); override; 
    Destructor Destroy; override; 
 
  Published 
    { Published declarations } 
    { --- Свойства --- } 
    Property Action; 
    Property Alignment : TAlignment 
       read fAlignment write fSetAlignment; 
    Property AllowGrayed : Boolean 
       read fAllowGrayed write fSetAllowGrayed; 
    Property Anchors; 
    Property BiDiMode; 
    Property Caption : String 
       read fCaption write fSetCaption; 
    Property CheckBoxType : TType 
       read fType write fSetType; 
    Property Checked : Boolean 
       read fChecked write fSetChecked; 
    Property Color : TColor 
       read fColor write fSetColor; 
    Property Constraints; 
    //Property Ctrl3D; 
    Property Cursor; 
    Property DragCursor; 
    Property DragKind; 
    Property DragMode; 
    Property Enabled; 
    Property Font : TFont 
       read fFont write fSetFont; 
    //Property Height; 
    Property HelpContext; 
    Property Hint; 
    Property Left; 
    Property Name; 
    //Property PartenBiDiMode; 
    Property ParentColor; 
    //Property ParentCtrl3D; 
    Property ParentFont; 
    Property ParentShowHint; 
    //Property PopMenu; 
    Property ShowHint; 
    Property State : TState 
       read fState write fSetState; 
    Property TabOrder; 
    Property TabStop; 
    Property Tag; 
    Property Top; 
    Property Visible; 
    //Property Width; 
    { --- Events --- } 
    Property OnClick; 
    Property OnContextPopup; 
    Property OnDragDrop; 
    Property OnDragOver; 
    Property OnEndDock; 
    Property OnEndDrag; 
    Property OnEnter; 
    Property OnExit; 
    Property OnKeyDown; 
    Property OnKeyPress; 
    Property OnKeyUp; 
    Property OnMouseDown; 
    Property OnMouseMove; 
    Property OnMouseUp; 
    Property OnStartDock; 
    Property OnStartDrag; 
  End; 
 
Procedure Register; //Hello! 
 
Implementation 
 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.KeyDown(var Key : Word; Shift : TShiftState); 
 
Begin 
If fFocus then 
   If Shift = [] then 
      If Key = 0032 then 
         Begin 
         fMouseState := msMouseDown; 
         If fState <> cbGrayed then 
            Begin 
            SetFocus; // Устанавливаем фокус на этот компонент 
                      // всем другим компонентам Windows посылает сообщение WM_KILLFOCUS. 
            fFocus := True; 
            Invalidate; 
            End; 
         End; 
Inherited KeyDown(Key,Shift); 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.KeyUp(var Key : Word; Shift : TShiftState); 
 
Begin 
If fFocus then 
   If Shift = [] then 
      If Key = 0032 then 
         Begin 
         If fState <> cbGrayed then 
            fSetChecked(not fChecked); // Изменяем состояние 
         fMouseState := msMouseUp; 
         End; 
Inherited KeyUp(Key,Shift); 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.WMSetFocus(var Message : TWMSetFocus); 
 
Begin 
fFocus := True; 
Invalidate; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.WMKillFocus(var Message : TWMKillFocus); 
 
Begin 
fFocus := False; // Удаляем фокус у всех компонент, которые не имеют фокуса. 
Invalidate; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetAlignment(A : TAlignment); 
 
Begin 
If A <> fAlignment then 
   Begin 
   fAlignment := A; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetType(T : TType); 
 
Begin 
If fType <> T then 
   Begin 
   fType := T; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetFont(cbFont : TFont); 
 
Var 
   FontChanged : Boolean; 
 
Begin 
FontChanged := False; 
 
If fFont.Style <> cbFont.Style then 
   Begin 
   fFont.Style := cbFont.Style; 
   FontChanged := True; 
   End; 
 
If fFont.CharSet <> cbFont.Charset then 
   Begin 
   fFont.Charset := cbFont.Charset; 
   FontChanged := True; 
   End; 
 
If fFont.Size <> cbFont.Size then 
   Begin 
   fFont.Size := cbFont.Size; 
   FontChanged := True; 
   End; 
 
If fFont.Name <> cbFont.Name then 
   Begin 
   fFont.Name := cbFont.Name; 
   FontChanged := True; 
   End; 
 
If fFont.Color <> cbFont.Color then 
   Begin 
   fFont.Color := cbFont.Color; 
   FontChanged := True; 
   End; 
 
If FontChanged then 
   Invalidate; 
End; 
{-------------------------------------------------------------------} 
procedure TCheckBoxX.MouseDown(Button: TMouseButton; Shift: TShiftState; 
  X, Y: Integer); 
 
Begin 
// Процедура MouseDown вызывается, когда кнопка мышки нажимается в пределах 
// кнопки, соответственно мы не можем получить значения координат X и Y. 
inherited MouseDown(Button, Shift, X, Y); 
fMouseState := msMouseDown; 
If fState <> cbGrayed then 
   Begin 
   SetFocus; // Устанавливаем фокус на этот компонент 
             // всем другим компонентам Windows посылает сообщение WM_KILLFOCUS. 
   fFocus := True; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
procedure TCheckBoxX.MouseUp(Button: TMouseButton; Shift: TShiftState; 
  X, Y: Integer); 
 
Begin 
// Процедура MouseUp вызывается, когда кнопка мышки отпускается в пределах 
// кнопки, соответственно мы не можем получить значения координат X и Y. 
inherited MouseUp(Button, Shift, X, Y); 
If fState <> cbGrayed then 
   fSetChecked(not fChecked); // Изменяем состояние 
fMouseState := msMouseUp; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetAllowGrayed(Bo : Boolean); 
 
Begin 
If fAllowGrayed <> Bo then 
   Begin 
   fAllowGrayed := Bo; 
   If not fAllowGrayed then 
      If fState = cbGrayed then 
         Begin 
         If fChecked then 
            fState := cbChecked 
         else 
            fState := cbUnChecked; 
         End; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetState(cbState : TState); 
 
Begin 
If fState <> cbState then 
   Begin 
   fState := cbState; 
   If (fState = cbChecked) then 
      fChecked := True; 
 
   If (fState = cbGrayed) then 
      fAllowGrayed := True; 
 
   If fState = cbUnChecked then 
      fChecked := False; 
 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetColor(C : TColor); 
 
Begin 
If fColor <> C then 
   Begin 
   fColor := C; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetCaption(S : String); 
 
Begin 
If fCaption <> S then 
   Begin 
   fCaption := S; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
Procedure TCheckBoxX.fSetChecked(Bo : Boolean); 
 
Begin 
If fChecked <> Bo then 
   Begin 
   fChecked := Bo; 
   If fState <> cbGrayed then 
      Begin 
      If fChecked then 
         fState := cbChecked 
      else 
         fState := cbUnChecked; 
      End; 
   Invalidate; 
   End; 
End; 
{-------------------------------------------------------------------} 
procedure TCheckBoxX.Paint;
 
var
  Buffer: array[0..127] of Char;
  I: Integer;
  fTextWidth, fTextHeight: Integer;
 
begin
{Get Delphi's componentname and initially write it in the caption}
  GetTextBuf(Buffer, SizeOf(Buffer));
  if Buffer <> '' then
    fCaption := Buffer;
 
  Canvas.Font.Size := Font.Size;
  Canvas.Font.Style := Font.Style;
  Canvas.Font.Color := Font.Color;
  Canvas.Font.Charset := Font.CharSet;
 
  fTextWidth := Canvas.TextWidth(fCaption);
  fTextHeight := Canvas.TextHeight('Q');
 
  if fAlignment = taRightJustify then
    begin
      fBoxTop := (Height - fRBoxHeight) div 2;
      fBoxLeft := 0;
      fTextTop := (Height - fTextHeight) div 2;
      fTextLeft := fBoxLeft + fRBoxWidth + 4;
    end
  else
    begin
      fBoxTop := (Height - fRBoxHeight) div 2;
      fBoxLeft := Width - fRBoxWidth;
      fTextTop := (Height - fTextHeight) div 2;
      fTextLeft := 1;
   //If fTextWidth > (Width - fBoxWidth - 4) then
   //   fTextLeft := (Width - fBoxWidth - 4) -  fTextWidth;
    end;
 
// выводим текст в caption
  Canvas.Pen.Color := fFont.Color;
  Canvas.Brush.Color := fColor;
  Canvas.TextOut(fTextLeft, fTextTop, fCaption);
 
// Рисуем контур фокуса
  if fFocus = True then
    Canvas.DrawFocusRect(Rect(fTextLeft - 1,
      fTextTop - 2,
      fTextLeft + fTextWidth + 1,
      fTextTop + fTextHeight + 2));
 
  if (fState = cbChecked) then
    Canvas.Brush.Color := clWindow;
 
  if (fState = cbUnChecked) then
    Canvas.Brush.Color := clWindow;
 
  if (fState = cbGrayed) then
    begin
      fAllowGrayed := True;
      Canvas.Brush.Color := clBtnFace;
    end;
 
// Создаём бокс clBtnFace когда кнопка мыши нажимается
// наподобие "стандартного" CheckBox
  if fMouseState = msMouseDown then
    Canvas.Brush.Color := clBtnFace;
 
  Canvas.FillRect(Rect(fBoxLeft + 2,
    fBoxTop + 2,
    fBoxLeft + fRBoxWidth - 2,
    fBoxTop + fRBoxHeight - 2));
 
// Рисуем прямоугольный чекбокс
  Canvas.Brush.Color := clBtnFace;
  Canvas.Pen.Color := clGray;
  Canvas.MoveTo(fBoxLeft + fRBoxWidth - 1, fBoxTop);
  Canvas.LineTo(fBoxLeft, fBoxTop);
  Canvas.LineTo(fBoxLeft, fBoxTop + fRBoxHeight);
 
  Canvas.Pen.Color := clWhite;
  Canvas.MoveTo(fBoxLeft + fRBoxWidth - 1, fBoxTop);
  Canvas.LineTo(fBoxLeft + fRBoxWidth - 1,
    fBoxTop + fRBoxHeight - 1);
  Canvas.LineTo(fBoxLeft - 1, fBoxTop + fRBoxHeight - 1);
 
  Canvas.Pen.Color := clBlack;
  Canvas.MoveTo(fBoxLeft + fRBoxWidth - 3, fBoxTop + 1);
  Canvas.LineTo(fBoxLeft + 1, fBoxTop + 1);
  Canvas.LineTo(fBoxLeft + 1, fBoxTop + fRBoxHeight - 2);
 
  Canvas.Pen.Color := clBtnFace;
  Canvas.MoveTo(fBoxLeft + fRBoxWidth - 2, fBoxTop + 1);
  Canvas.LineTo(fBoxLeft + fRBoxWidth - 2,
    fBoxTop + fRBoxHeight - 2);
  Canvas.LineTo(fBoxLeft, fBoxTop + fRBoxHeight - 2);
 
// Теперь он должен быть таким же как чекбокс в Delphi
 
  if fChecked then
    begin
      Canvas.Pen.Color := clBlack;
      Canvas.Brush.Color := clBlack;
 
   // Рисуем прямоугольник
      if fType = cbRect then
        begin
          Canvas.FillRect(Rect(fBoxLeft + 4, fBoxTop + 4,
            fBoxLeft + fRBoxWidth - 4, fBoxTop + fRBoxHeight - 4));
        end;
 
   // Рисуем значёк "о"
      if fType = cbBullet then
        begin
          Canvas.Ellipse(fBoxLeft + 4, fBoxTop + 4,
            fBoxLeft + fRBoxWidth - 4, fBoxTop + fRBoxHeight - 4);
        end;
 
   // Рисуем крестик
      if fType = cbCross then
        begin
      {Right-top to left-bottom}
          Canvas.MoveTo(fBoxLeft + fRBoxWidth - 5, fBoxTop + 3);
          Canvas.LineTo(fBoxLeft + 2, fBoxTop + fRBoxHeight - 4);
          Canvas.MoveTo(fBoxLeft + fRBoxWidth - 4, fBoxTop + 3);
          Canvas.LineTo(fBoxLeft + 2, fBoxTop + fRBoxHeight - 3);
          Canvas.MoveTo(fBoxLeft + fRBoxWidth - 4, fBoxTop + 4);
          Canvas.LineTo(fBoxLeft + 3, fBoxTop + fRBoxHeight - 3);
      {Left-top to right-bottom}
          Canvas.MoveTo(fBoxLeft + 3, fBoxTop + 4);
          Canvas.LineTo(fBoxLeft + fRBoxWidth - 4,
            fBoxTop + fRBoxHeight - 3);
          Canvas.MoveTo(fBoxLeft + 3, fBoxTop + 3);
          Canvas.LineTo(fBoxLeft + fRBoxWidth - 3,
            fBoxTop + fRBoxHeight - 3); //mid
          Canvas.MoveTo(fBoxLeft + 4, fBoxTop + 3);
          Canvas.LineTo(fBoxLeft + fRBoxWidth - 3,
            fBoxTop + fRBoxHeight - 4);
        end;
 
   // Рисуем галочку
      if fType = cbMark then
        for I := 0 to 2 do
          begin
         {Left-mid to left-bottom}
            Canvas.MoveTo(fBoxLeft + 3, fBoxTop + 5 + I);
            Canvas.LineTo(fBoxLeft + 6, fBoxTop + 8 + I);
         {Left-bottom to right-top}
            Canvas.MoveTo(fBoxLeft + 6, fBoxTop + 6 + I);
            Canvas.LineTo(fBoxLeft + 10, fBoxTop + 2 + I);
          end;
 
   // Рисуем бриллиантик
      if fType = cbDiamond then
        begin
          Canvas.Pixels[fBoxLeft + 06, fBoxTop + 03] := clBlack;
          Canvas.Pixels[fBoxLeft + 06, fBoxTop + 09] := clBlack;
 
          Canvas.MoveTo(fBoxLeft + 05, fBoxTop + 04);
          Canvas.LineTo(fBoxLeft + 08, fBoxTop + 04);
 
          Canvas.MoveTo(fBoxLeft + 05, fBoxTop + 08);
          Canvas.LineTo(fBoxLeft + 08, fBoxTop + 08);
 
          Canvas.MoveTo(fBoxLeft + 04, fBoxTop + 05);
          Canvas.LineTo(fBoxLeft + 09, fBoxTop + 05);
 
          Canvas.MoveTo(fBoxLeft + 04, fBoxTop + 07);
          Canvas.LineTo(fBoxLeft + 09, fBoxTop + 07);
 
          Canvas.MoveTo(fBoxLeft + 03, fBoxTop + 06);
          Canvas.LineTo(fBoxLeft + 10, fBoxTop + 06); // middle line
        end;
    end;
end;
 
{-------------------------------------------------------------------} 
procedure Register;
begin
  RegisterComponents('Samples', [TCheckBoxX]);
end;
{-------------------------------------------------------------------}
 
destructor TCheckBoxX.Destroy;
 
begin
  inherited Destroy;
end;
{-------------------------------------------------------------------}
 
constructor TCheckBoxX.Create(AOwner: TComponent);
 
begin
  inherited Create(AOwner);
  Height := 17;
  Width := 97;
  fChecked := False;
  fColor := clBtnFace;
  fState := cbUnChecked;
  fFont := inherited Font;
  fAllowGrayed := False;
  fFocus := False;
  fMouseState := msMouseUp;
  fAlignment := taRightJustify;
  TabStop := True; // Sorry
end;
{-------------------------------------------------------------------}
end.
{===================================================================}

Взято из https://forum.sources.ru