Title: Tired of Delphi's checkboxes?
Question: Tired of Delphi's checkboxes?
Answer:
{
====================================================================
This is a DELPHI 5 Visual Component
====================================================================
In WIN3.1 you have a checkbox with an "X" check. In WIN95 and WINNT
you have a checkbox with a "V" check. In Delphi's standard palette
you think you'll get a checkbox with an "X" check, but you'll get a
checkbox with a "V" check instead. Maybe Borland/Inprise didn't
update the palette bitmap going from W3.1 to W95/W98.
Anyway, this is a checkbox with an "X", or a "V", or a "o", or a
rect, or a diamond check. This component is tested under WIN95 and
WINNT. This component will be registered under "Samples". You are
allowed to alter this component. For remarks, suggestions,
improvements, enhancements please email:
M.deHaan@inn.nl
====================================================================
Explanation
====================================================================
X = cross
V = mark
o = bullet
+-+
|W| = rect
+-+
/\
= diamond
\/
(W = means filled)
====================================================================
Features of this checkbox
====================================================================
You'll find many checkboxes on the web. Try them. You will find out
that when you put more than one of these checkboxes, on a form,
together with some "Delphi checkboxes", the focus rectangle will
not work properly, if there is one. All those checkboxes didn't
implement a WM_KILLFOCUS message interceptor. This checkbox does.
====================================================================
Functionality
====================================================================
The functionality of this CheckBoxX slightly differs from Delphi's
TCheckBox. I thought this functionality makes a little bit more
sense. But you may alter the functionality, if you disagree with me.
The slightly altered functionality regards the properties:
"AllowGrayed", "Checked" and "State".
====================================================================
30-08-00
Keystrokes implemented
(Tab, Spacebar)
====================================================================
}
Unit CheckBoxX;
Interface
Uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
Const
{ Other constants }
fRBoxWidth : Integer = 13; // Width of rectangular checkbox
fRBoxHeight : Integer = 13; // Height of rectangular checkbox
Type
TState = (cbUnchecked,cbChecked,cbGrayed); // The same
// as in Delphi
TType = (cbCross,cbMark,cbBullet,cbDiamond,cbRect); // Added
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; // top of text
fTextLeft : Integer; // left of text
fBoxTop : Integer; // top of box
fBoxLeft : Integer; // left of box
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; // Yes, this removes the focus rect!
Procedure WMSetFocus(var Message : TWMSetFocus);
Message WM_SETFOCUS; // If you are using the TAB or
// Shift-Tab key
Procedure KeyDown(var Key : Word; Shift : TShiftState); override;
// Interception of KeyDown
Procedure KeyUp(var Key : Word; Shift : TShiftState); override;
// Interception of KeyUp
Public
{ Public declarations }
// If you put Create and Destroy under protected,
// Delphi complains about that.
Constructor Create(AOwner : TComponent); override;
Destructor Destroy; override;
Published
{ Published declarations }
{ --- Properties --- }
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; // Set focus to this component
// Windows sends a WM_KILLFOCUS message to all the
// other components.
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); // Change the check
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; // Remove the focus rectangle of all the components,
// which doesn't have the focus.
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
// The MouseDown procedure is only called when the mouse
// goes down WITHIN the control, so we don't have to check
// the X and Y values.
inherited MouseDown(Button, Shift, X, Y);
fMouseState := msMouseDown;
If fState cbGrayed then
Begin
SetFocus; // Set focus to this component
// Windows sends a WM_KILLFOCUS message to all the
// other components.
fFocus := True;
Invalidate;
End;
End;
{-------------------------------------------------------------------}
procedure TCheckBoxX.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
Begin
// The MouseUp procedure is only called when the mouse
// goes up WITHIN the control, so we don't have to check
// the X and Y values.
inherited MouseUp(Button, Shift, X, Y);
If fState cbGrayed then
fSetChecked(not fChecked); // Change the check
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;
// Write the caption
Canvas.Pen.Color := fFont.Color;
Canvas.Brush.Color := fColor;
Canvas.TextOut(fTextLeft,fTextTop,fCaption);
// Draw the focus rectangle
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;
// Make the box clBtnFace when the mouse is down
// just like the "standard" CheckBox
If fMouseState = msMouseDown then
Canvas.Brush.Color := clBtnFace;
Canvas.FillRect(Rect(fBoxLeft + 2,
fBoxTop + 2,
fBoxLeft + fRBoxWidth - 2,
fBoxTop + fRBoxHeight - 2));
// Draw the rectangular checkbox
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);
// Now it should be exactly the same as the Delphi checkbox
If fChecked then
Begin
Canvas.Pen.Color := clBlack;
Canvas.Brush.Color := clBlack;
// Paint the rectangle
If fType = cbRect then
Begin
Canvas.FillRect(Rect(fBoxLeft + 4,fBoxTop + 4,
fBoxLeft + fRBoxWidth - 4,fBoxTop + fRBoxHeight - 4));
End;
// Paint the bullet
If fType = cbBullet then
Begin
Canvas.Ellipse(fBoxLeft + 4,fBoxTop + 4,
fBoxLeft + fRBoxWidth - 4,fBoxTop + fRBoxHeight - 4);
End;
// Paint the cross
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;
// Paint the mark
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;
// Paint the diamond
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.
{===================================================================}