The component below allows you to set NullEqualUnChecked value. This
will solve the problem.
Quote
Jim Lowell wrote:
> I am writing an application which required the use of check boxes to display
> some binary data. I have found that the TDBCheckBox works great if the data is
> defined, but that if it is doesn't exist (e.g. data is in a non-existant detail
> record) or hasn't been explicitly defined (i.e. is neither True nor False) the
> check box displays Checked/Greyed. To the casual user, the box looks checked,
> as the "greyed" area is not obviously greyed unless an ungreyed check box is
> right next to it.
> I can't figure out how to get the system to display null data as unchecked.
> Does anyone have a solution to this problem?
> Thanks,
> Jim Lowell
unit dbcb;
interface
uses
SysUtils, Windows, Messages, Classes, Controls, Forms,
Graphics, Menus, StdCtrls, ExtCtrls, DB,DBCtrls, DBTables, Mask,
Buttons;
//******************************************
type
TDBCheckBoxEnhanced = class(TCustomCheckBox)
private
FDataLink: TFieldDataLink;
FValueCheck: string;
FValueUncheck: string;
FPaintControl: TPaintControl;
FNullEqualUnChecked:Boolean;
FAllowFocus:Boolean;
procedure DataChange(Sender: TObject);
function GetDataField: string;
function GetDataSource: TDataSource;
function GetField: TField;
function GetFieldState: TCheckBoxState;
function GetReadOnly: Boolean;
function GetNull: Boolean;
procedure SetDataField(const Value: string);
procedure SetDataSource(Value: TDataSource);
procedure SetReadOnly(Value: Boolean);
procedure SetNull(Value: Boolean);
procedure SetAllowFocus(Value: Boolean);
procedure SetValueCheck(const Value: string);
procedure SetValueUncheck(const Value: string);
procedure UpdateData(Sender: TObject);
function ValueMatch(const ValueList, Value: string): Boolean;
procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
procedure CMExit(var Message: TCMExit); message CM_EXIT;
procedure CMGetDataLink(var Message: TMessage); message
CM_GETDATALINK;
procedure WMNCHitTest(var Message: TWMNCHitTest); message
WM_NCHITTEST;
protected
procedure Toggle; override;
procedure KeyPress(var Key: Char); override;
procedure Notification(AComponent: TComponent;Operation:
TOperation); override;
procedure WndProc(var Message: TMessage); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Checked;
property Field: TField read GetField;
property State;
published
property Alignment;
property AllowGrayed;
property Caption;
property Color;
property Ctl3D;
property DataField: string read GetDataField write SetDataField;
property DataSource: TDataSource read GetDataSource write
SetDataSource;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property NullEqualUnChecked: Boolean read GetNull write SetNull
default True;
property AllowFocus: Boolean read FAllowFocus write SetAllowFocus
default True;
property ParentColor;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ReadOnly: Boolean read GetReadOnly write SetReadOnly
default False;
property ShowHint;
property TabOrder;
property TabStop;
property ValueChecked: string read FValueCheck write SetValueCheck;
property ValueUnchecked: string read FValueUncheck write
SetValueUncheck;
property Visible;
property OnClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
end;
procedure Register;
implementation
uses BDE, Clipbrd, DBConsts, Dialogs;
//***********************************************
constructor TDBCheckBoxEnhanced.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := ControlStyle + [csReplicatable];
State := cbUnchecked;
FDataLink := TFieldDataLink.Create;
FValueCheck := STextTrue;
FValueUncheck := STextFalse;
FDataLink.Control := Self;
FDataLink.OnDataChange := DataChange;
FDataLink.OnUpdateData := UpdateData;
FPaintControl := TPaintControl.Create(Self, 'BUTTON');
FPaintControl.Ctl3DButton := True;
FNullEqualUnChecked:=True;
FAllowFocus:=True;
end;
destructor TDBCheckBoxEnhanced.Destroy;
begin
FPaintControl.Free;
FDataLink.Free;
FDataLink := nil;
inherited Destroy;
end;
procedure TDBCheckBoxEnhanced.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (Operation = opRemove) and (FDataLink <> nil) and
(AComponent = DataSource) then DataSource := nil;
end;
function TDBCheckBoxEnhanced.GetFieldState: TCheckBoxState;
var
Text: string;
begin
if FDatalink.Field <> nil then
if FDataLink.Field.IsNull then begin
if FNullEqualUnChecked then Result:=cbUnChecked else Result :=
cbGrayed;
end
else if FDataLink.Field.DataType = ftBoolean then
if FDataLink.Field.AsBoolean then
Result := cbChecked
else
Result := cbUnchecked
else
begin
if FNullEqualUnChecked then Result:=cbUnChecked else Result :=
cbGrayed;
Text := FDataLink.Field.Text;
if ValueMatch(FValueCheck, Text) then Result := cbChecked else
if ValueMatch(FValueUncheck, Text) then Result := cbUnchecked;
end
else
Result := cbUnchecked;
end;
procedure TDBCheckBoxEnhanced.DataChange(Sender: TObject);
begin
State := GetFieldState;
end;
procedure TDBCheckBoxEnhanced.UpdateData(Sender: TObject);
var
Pos: Integer;
S: string;
begin
if State = cbGrayed then
FDataLink.Field.Clear
else
if FDataLink.Field.DataType = ftBoolean then
FDataLink.Field.AsBoolean := Checked
else
begin
if Checked then S := FValueCheck else S := FValueUncheck;
Pos := 1;
FDataLink.Field.Text := ExtractFieldName(S, Pos);
end;
end;
function TDBCheckBoxEnhanced.ValueMatch(const ValueList, Value: string):
Boolean;
var
Pos: Integer;
begin
Result := False;
Pos := 1;
while Pos <= Length(ValueList) do
if AnsiCompareText(ExtractFieldName(ValueList, Pos), Value) = 0 then
begin
Result := True;
Break;
end;
end;
procedure TDBCheckBoxEnhanced.Toggle;
begin
if FDataLink.Edit then
begin
inherited Toggle;
FDataLink.Modified;
FDataLink.UpdateRecord;
end;
end;
function TDBCheckBoxEnhanced.GetDataSource: TDataSource;
begin
Result := FDataLink.DataSource;
end;
procedure TDBCheckBoxEnhanced.SetDataSource(Value: TDataSource);
begin
FDataLink.DataSource := Value;
if Value <> nil then Value.FreeNotification(Self);
end;
function TDBCheckBoxEnhanced.GetDataField: string;
begin
Result := FDataLink.FieldName;
end;
procedure TDBCheckBoxEnhanced.SetDataField(const Value: string);
begin
FDataLink.FieldName := Value;
end;
function TDBCheckBoxEnhanced.GetReadOnly: Boolean;
begin
Result := FDataLink.ReadOnly;
end;
procedure TDBCheckBoxEnhanced.SetReadOnly(Value: Boolean);
begin
FDataLink.ReadOnly := Value;
end;
procedure TDBCheckBoxEnhanced.SetAllowFocus(Value: Boolean);
begin
FAllowFocus:=Value;
If Not Value then TabStop:=False;
end;
procedure TDBCheckBoxEnhanced.SetNull(Value: Boolean);
begin
FNullEqualUnChecked := Value;
end;
function TDBCheckBoxEnhanced.GetNull: Boolean;
begin
Result := FNullEqualUnChecked;
end;
function TDBCheckBoxEnhanced.GetField: TField;
begin
Result := FDataLink.Field;
end;
procedure TDBCheckBoxEnhanced.KeyPress(var Key: Char);
begin
inherited KeyPress(Key);
case Key of
#8, ' ':
FDataLink.Edit;
#27:
FDataLink.Reset;
end;
end;
procedure TDBCheckBoxEnhanced.SetValueCheck(const Value: string);
begin
FValueCheck := Value;
DataChange(Self);
end;
procedure TDBCheckBoxEnhanced.SetValueUncheck(const Value: string);
begin
FValueUncheck := Value;
DataChange(Self);
end;
procedure TDBCheckBoxEnhanced.WndProc(var Message: TMessage);
begin
with Message do
if (Msg = WM_CREATE) or (Msg = WM_WINDOWPOSCHANGED) or
(Msg = CM_TEXTCHANGED) or (Msg = CM_FONTCHANGED) then
FPaintControl.DestroyHandle;
inherited;
end;
procedure TDBCheckBoxEnhanced.WMPaint(var Message: TWMPaint);
begin
if not (csPaintCopy in ControlState) then inherited else
begin
SendMessage(FPaintControl.Handle, BM_SETCHECK, Ord(GetFieldState),
0);
SendMessage(FPaintControl.Handle, WM_PAINT, Message.DC, 0);
end;
end;
procedure TDBCheckBoxEnhanced.CMExit(var Message: TCMExit);
begin
try
FDataLink.UpdateRecord;
except
SetFocus;
raise;
end;
inherited;
end;
procedure TDBCheckBoxEnhanced.CMGetDataLink(var Message: TMessage);
begin
Message.Result := Integer(FDataLink);
end;
procedure TDBCheckBoxEnhanced.WMNCHitTest(var Message: TWMNCHitTest);
begin
with Message do
if (csDesigning in ComponentState) and (Parent <> nil) then
Result := HTCLIENT
else begin
If FAllowFocus then result:=HTClient else Result:=0;
end;
{ inherited};
end;
procedure Register;
begin
RegisterComponents('Data Controls', [TDBCheckBoxEnhanced]);
end;
end.