MyCheckBox

 MyCheckBoxは、MyRadioButtonと同じで、フォントと、フォントの領域に色をつけられる様にしたものです。
TCanvasを追加して、文字と、文字領域を描画し指定された色をつけています。

サンプル1サンプル2

右側が、マウスカーソルが、CheckBoxの領域内にはいった場合で、MyRadioButton と同じ様に、明るさを変えています。
色によっては、明るい色が正しく表現できない場合があります、その時は、色をの変化を作り出す係数を変更して下さい。

unit MyCheckBox;

interface

uses
  Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Buttons, ExtCtrls, CommCtrl;

type
  TMyCheckBox = class(TButton)
  private
    FCanvas: TCanvas;
    IsFocused: Boolean;
    FMouseInControl: Boolean;
    FFocusedFrame: Boolean;
    FChecked: Boolean;
    FAlignment: TLeftRight;
    procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    procedure SetFocusedFrame(Varue: Boolean);
    procedure SetAlignment(Value: TLeftRight);
    procedure MouseInFillRect(PRect: Trect; PColor: Tcolor);
    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
  protected
    function GetChecked: Boolean; override;
    procedure SetChecked(Value: Boolean); override;
    procedure CreateParams(var Params: TCreateParams); override;
    procedure CreateWnd; override;
    procedure SetButtonStyle(ADefault: Boolean); override;
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CNMeasureItem(var Message: TWMMeasureItem ); message CN_MEASUREITEM;
    procedure CNDrawItem(var Message: TWMDrawItem); message CN_DRAWITEM;
    procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
    procedure DrawButton(DrawItemStruct: TDrawItemStruct);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Canvas: TCanvas read FCanvas;
  published
    property Alignment: TLeftRight read FAlignment write SetAlignment default taLeftJustify;
    property Checked: Boolean read GetChecked write SetChecked default False;
    property Color;
    property ParentColor;
    property FocusedFrame: Boolean read FFocusedFrame write SetFocusedFrame default True;
  end;

procedure Register;

//////////////////////////////////////////////////////////////////////////////
implementation

uses SysUtils, Themes;

procedure Register;
begin
  RegisterComponents('MyVCL', [TMyCheckBox]);
end;

constructor TMyCheckBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FCanvas := TCanvas.Create;
  FFocusedFrame := True;
end;

destructor TMyCheckBox.Destroy;
begin
  inherited Destroy;
  FCanvas.Free;
end;

procedure TMyCheckBox.SetButtonStyle(ADefault: Boolean);
begin
  if ADefault <> IsFocused then
  begin
    IsFocused := ADefault;
    Refresh;
  end;
end;

procedure TMyCheckBox.SetAlignment(Value: TLeftRight);
begin
  if FAlignment <> Value then
  begin
    FAlignment := Value;
    Invalidate;
  end;
end;

// テーマ有効時フォーカス点々枠表示非表示設定
procedure TMyCheckBox.SetFocusedFrame(Varue: Boolean);
begin
  if Varue <> FFocusedFrame then
  begin
    FFocusedFrame := Varue;
    Refresh;
  end;
end;

procedure TMyCheckBox.CreateParams(var Params: TCreateParams);
begin
  inherited CreateParams(Params);
  with Params do Style := Style or BS_OWNERDRAW;
end;

procedure TMyCheckBox.CNMeasureItem(var Message: TWMMeasureItem);
begin
  with Message.MeasureItemStruct^ do
  begin
    itemWidth := Width;
    itemHeight := Height;
  end;
end;

procedure TMyCheckBox.CNDrawItem(var Message: TWMDrawItem);
var
  SaveIndex: Integer;
begin
  with Message.DrawItemStruct^ do
  begin
    SaveIndex := SaveDC(hDC);
    FCanvas.Lock;
    try
      FCanvas.Handle := hDC;
      FCanvas.Font := Font;
      FCanvas.Brush := Brush;
      DrawButton(Message.DrawItemStruct^);
    finally
      FCanvas.Handle := 0;
      FCanvas.Unlock;
      RestoreDC(hDC, SaveIndex);
    end;
  end;
  Message.Result := 1;
end;

procedure TMyCheckBox.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  Invalidate;
end;

procedure TMyCheckBox.CMFontChanged(var Message: TMessage);
begin
  inherited;
  Invalidate;
end;


procedure TMyCheckBox.WMLButtonDblClk(var Message: TWMLButtonDblClk);
begin
  Perform(WM_LBUTTONDOWN, Message.Keys, Longint(Message.Pos));
end;

procedure TMyCheckBox.MouseInFillRect(PRect: Trect; PColor: Tcolor);
begin
  FCanvas.Brush.Color := PColor;
  FCanvas.Pen.Color := PColor;
  if ThemeServices.ThemesEnabled then // テーマなら
  begin
    FCanvas.MoveTo(PRect.Left + 1, PRect.Top - 1);
    FCanvas.LineTo(PRect.Right - 1, PRect.Top - 1);
    FCanvas.MoveTo(PRect.Left + 1, PRect.Bottom);
    FCanvas.LineTo(PRect.Right - 1, PRect.Bottom);
    FCanvas.FillRect(PRect);
  end
  else
  begin
    PRect.Top := PRect.Top - 1;
    FCanvas.FillRect(PRect);
    FCanvas.MoveTo(PRect.Left, PRect.Bottom);
    FCanvas.LineTo(PRect.Right, PRect.Bottom);
  end;

end;

procedure TMyCheckBox.DrawButton(DrawItemStruct: TDrawItemStruct);
const
  BoxSize = 13; // CHECKBOX SIZE;
var
  Flags: Longint;
  IsDown, IsDefault, IsDisabled: Boolean;
  ORGRect, CRect, TextRect, SRect: TRect;
  defCTop: integer;
  defPTop, defPRight, defPBottom: integer;
  BriteColor : integer;
  Button : TThemedButton;
  Details: TThemedElementDetails;
begin
  FCanvas.Handle := DrawItemStruct.hDC;

  ORGRect := ClientRect;
  if (ORGRect.Right - ORGRect.Left) mod 2 = 0 then ORGRect.Right := ORGRect.Right - 1;
  if (ORGRect.Bottom - ORGRect.Top) mod 2 = 0 then ORGRect.Bottom := ORGRect.Bottom - 1;

  SRect := ORGRect;
  SRect.Top := ORGRect.Top + 1;
  SRect.Bottom := ORGRect.Bottom - 1;
  defCTop := (ORGRect.Bottom - ORGRect.Top - BoxSize) div 2 + ORGRect.Top;
  defPTop := (ORGRect.Bottom - ORGRect.Top - abs(FCanvas.Font.Height)) div 2 + ORGRect.Top;
  defPBottom := defPTop + abs(FCanvas.Font.Height);

  if FAlignment = taLeftJustify then
  begin
    CRect := Rect(3, defCTop, BoxSize + 3, defCTop + BoxSize);
    defPRight := ORGRect.Left + BoxSize + 5 + FCanvas.TextWidth(Caption);
    TextRect := Rect(ORGRect.Left + BoxSize + 5, defPTop, defPRight, defPBottom);
    DrawItemStruct.rcItem.Right := DrawItemStruct.rcItem.Left + 16;
    DrawItemStruct.rcItem.Left := DrawItemStruct.rcItem.Left + 1;
  end
  else
  begin
    CRect := Rect(ORGRect.Right - BoxSize - 3, defCTop, ORGRect.Right - 3, defCTop + BoxSize);
    defPRight := ORGRect.Left + 2 + FCanvas.TextWidth(Caption);
    TextRect := Rect(ORGRect.Left + 2, defPTop, defPRight, defPBottom);
    DrawItemStruct.rcItem.Left := DrawItemStruct.rcItem.Right - 16;
  end;

  with DrawItemStruct do
  begin
    FCanvas.Handle := hdc;
    FCanvas.Font := Self.Font;
    IsDown := itemState and ODS_SELECTED <> 0;
    IsDefault := itemState and ODS_FOCUS <> 0;
    IsDisabled := itemState and ODS_DISABLED <> 0;
  end;

  BriteColor := Color;
  if Color <> clbtnface then
  begin
    if BriteColor and $00FF0000 >= $00DF0000 then BriteColor := BriteColor or $00FF0000;
    if BriteColor and $0000FF00 >= $0000DF00 then BriteColor := BriteColor or $0000FF00;
    if BriteColor and $000000FF >= $000000DF then BriteColor := BriteColor or $000000FF;
    if BriteColor and $FFFF0000 < $00DF0000 then BriteColor := BriteColor + $00200000;
    if BriteColor and $FF00FF00 < $0000DF00 then BriteColor := BriteColor + $00002000;
    if BriteColor and $FF0000FF < $000000DF then BriteColor := BriteColor + $00000020;
  end
  else BriteColor := ClWhite;

//
  if ThemeServices.ThemesEnabled then // テーマなら
  begin
    PerformEraseBackGround(Self,Canvas.Handle);
    if FChecked then
    begin
      if not Enabled then
        Button := tbCheckBoxCheckedDisabled
      else
        if isDown then
          Button := tbCheckBoxCheckedPressed
        else
          if FMouseInControl then
            Button := tbCheckBoxCheckedHot
          else
            Button := tbCheckBoxCheckedNormal;
    end
    else
    begin
      if not Enabled then
        Button := tbCheckBoxUnCheckedDisabled
      else
        if isDown then
          Button := tbCheckBoxUnCheckedPressed
        else
          if FMouseInControl then
            Button := tbCheckBoxUnCheckedHot
          else
            Button := tbCheckBoxUnCheckedNormal;
    end;
    Details := ThemeServices.GetElementDetails(Button);
//    ThemeServices.DrawParentBackground(Handle, DrawItemStruct.hdc, @Details, True);

    if FMouseInControl then
      MouseInFillRect(SRect, BriteColor)
    else
      MouseInFillRect(SRect, Color);

    ThemeServices.DrawElement(DrawItemStruct.hdc, Details, DrawItemStruct.rcItem);
  end
  else
  begin
    Flags := DFCS_BUTTONCHECK;
    if IsDown then Flags := Flags or DFCS_PUSHED;
    if IsDisabled then Flags := Flags or DFCS_INACTIVE;
    if FChecked then Flags := Flags or DFCS_CHECKED;

    if FMouseInControl then
      MouseInFillRect(SRect, BriteColor)
    else
      MouseInFillRect(SRect, Color);

    DrawFrameControl(FCanvas.Handle, CRect, DFC_BUTTON, Flags);
  end;

// Caption set
  if IsDisabled then
    DrawState( FCanvas.Handle, FCanvas.Brush.Handle, nil, Integer(Caption), 0,
               TextRect.Left,TextRect.Top, 0, 0, DST_TEXT or DSS_DISABLED)
  else
    DrawText(FCanvas.Handle, PChar(Caption), -1, TextRect, DT_SINGLELINE or DT_CENTER or DT_VCENTER);
// Focuse Frame Draw
  if IsFocused and IsDefault and FFocusedFrame then
  begin
    InflateRect(ORGRect, 0, 0);
    FCanvas.Pen.Color := clWindowFrame;
    FCanvas.Font.Color := clBlack;
    FCanvas.Brush.Color := clBtnFace;
    DrawFocusRect(FCanvas.Handle, ORGRect);
  end;
end;

function TMyCheckBox.GetChecked: Boolean;
begin
  Result := FChecked;
  Refresh;
end;

procedure TMyCheckBox.SetChecked(Value: Boolean);
begin
  if FChecked <> Value then
  begin
    FChecked := Value;
    TabStop := Value;
    if HandleAllocated then
      SendMessage(Handle, BM_SETCHECK, Integer(Checked), 0);
    if Value then
    begin
      inherited Changed;
      if not ClicksDisabled then Click;
    end;
  end;
end;

procedure TMyCheckBox.CreateWnd;
begin
  inherited CreateWnd;
  SendMessage(Handle, BM_SETCHECK, Integer(FChecked), 0);
end;

procedure TMyCheckBox.CNCommand(var Message: TWMCommand);
begin
  case Message.NotifyCode of
      BN_CLICKED: if FChecked then SetChecked(False)
                  else SetChecked(True);
      BN_DOUBLECLICKED: DblClick;
  end;
end;

procedure TMyCheckBox.CMMouseEnter(var Message: TMessage);
begin
  inherited;
  if not FMouseinControl and not (csDesigning in ComponentState) then
  begin
    FMouseInControl := True;
    if Enabled then Repaint;
  end;
end;

procedure TMyCheckBox.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  if FMouseinControl then
  begin
    FMouseInControl := False;
    if Enabled then Repaint;
  end;
end;

end.


    download MyCheckBox.zip

      コンポーネント一覧へ戻る