D4: Making TCheckbox Data Aware with TDBEdit

Simple means of making some components data-aware. Alternative data-aware checkboxes (and radiobuttons) that can be arranged more flexibly.

Although more recent versions of Delphi may offer better ways of displaying data-aware collections of checkboxes and radiobuttons, I'm still using D4. I have often wished for a data-aware component that (a) does not include the bevelled box of  D4's radio button group, (b) can be made to resemble some paper forms more closely, (c) permits more flexible arrangement of the items in the group, and (d) permits unusual patterns of buttons to be 'on' and 'off' simultaneously.

In short, more flexibility.

I think this recipe does this, and it also illustrates simple means for making some controls that are not data-aware acquire this capability by co-operating with those that are.

delphi.jpg

The upper and lower rows of checkboxes are represented in the Delphi code below by the classes TCheckboxCollection and TPersonalityCBCollection respectively. Each of these classes is a container for checkbox descriptors and their methods, Click, GetValue and SetValue, establish the behaviour of controls collectively, and arrange to associate their collective value with the associated data-aware control and, hence, with the data store.

The upper set of checkboxes behaves much like a set of radio buttons. In contrast, more than one of the set of lower checkboxes can be checked at once, and the "RESET" checkbox can be used to remove the checks from all at once.

Your comments welcome!

unit Unit1;



interface



uses

Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,

Db, StdCtrls, Mask, DBCtrls, DBTables, ExtCtrls;



type



TCheckboxDescriptor = class

// hide the default behaviour of the checkbox in response

// to a click, and simplify manipulation of the encapsulated object

private

preClickedState: TCheckBoxState;

function GetState: TCheckBoxState;

procedure SetState ( State: TCheckBoxState );

public

checkbox: TCheckbox;

property State: TCheckBoxState read GetState write SetState;

constructor Create (theCheckbox: TCheckbox);

end;



TCheckboxCollection = class

// associate a data-aware edit box and its value with a collection

// of checkbox descriptors; default behaviour resembles radio buttons

checkboxDescriptors: TList;

handlingClick: Boolean;

private

function FindSender ( Sender: TObject ): TCheckboxDescriptor;

function GetValue : string;

procedure SetValue ( NewValue: string );

public

associatedDBEdit: TDBEdit;

constructor Create ( DBEdit: TDBEdit; theCheckboxes: array of TCheckbox );

procedure Click ( Sender: TObject );

property Value: string read GetValue write SetValue;

end;



TPersonalityCBCollection = class ( TCheckboxCollection )

// derived class which permits more than one checkbox to be checked at

// a time, and uses one checkbox for resetting the others

private

function GetValue : string;

procedure SetValue ( NewValue: string );

public

property Value: string read GetValue write SetValue;

procedure Click ( Sender: TObject );

end;



TForm1 = class(TForm)

Table1: TTable;

DBEdit1: TDBEdit;

DataSource1: TDataSource;

CheckBox1: TCheckBox;

CheckBox2: TCheckBox;

CheckBox3: TCheckBox;

CheckBox4: TCheckBox;

CheckBox5: TCheckBox;

CheckBox6: TCheckBox;

CheckBox7: TCheckBox;

CheckBox8: TCheckBox;

CheckBoxNA: TCheckBox;

CheckBox9: TCheckBox;

CheckBox10: TCheckBox;

CheckBox11: TCheckBox;

CheckBox12: TCheckBox;

CheckBox13: TCheckBox;

CheckBox14: TCheckBox;

CheckBox15: TCheckBox;

CheckBox16: TCheckBox;

DBNavigator1: TDBNavigator;

Label1: TLabel;

Label2: TLabel;

Label3: TLabel;

Shape1: TShape;

Label4: TLabel;

DBEdit2: TDBEdit;

procedure FormCreate(Sender: TObject);

procedure CheckBoxNAClick(Sender: TObject);

procedure DBEdit1Change(Sender: TObject);

procedure CheckBox9Click(Sender: TObject);

procedure DBEdit2Change(Sender: TObject);

private

SeverityCBs: TCheckboxCollection;

PersonalityCBs: TPersonalityCBCollection;

public

end;



var

Form1: TForm1;



implementation



{$R *.DFM}



constructor TCheckboxDescriptor.Create (theCheckbox: TCheckbox);

begin

inherited Create;

checkbox:=theCheckbox;

// retain the design state of the checkbox

preClickedState:=theCheckbox.State;

end;



function TCheckboxDescriptor.GetState: TCheckBoxState;

begin

result:=preClickedState;

end;



procedure TCheckboxDescriptor.SetState ( State: TCheckBoxState );

begin

checkbox.State:=State;

preClickedState:=State

end;



constructor TCheckboxCollection.Create ( DBEdit: TDBEdit; theCheckboxes: array of TCheckbox );

var

i: integer;

begin

inherited Create;

associatedDBEdit:=DBEdit;

checkboxDescriptors:=TList.Create;

for i:=0 to high ( theCheckboxes ) do

checkboxDescriptors.Add(TCheckboxDescriptor.Create(theCheckboxes[i]));

handlingClick:=false;

end;



function TCheckboxCollection.FindSender ( Sender: TObject ): TCheckboxDescriptor;

var

c: integer;

checkboxDescriptor: TCheckboxDescriptor;

begin

checkboxDescriptor:=nil;

for c:=0 to checkboxDescriptors.Count - 1 do begin

checkboxDescriptor:=checkboxDescriptors.Items[c];

if checkboxDescriptor.checkbox = Sender then break

end;

result:=checkboxDescriptor

end;



procedure TCheckboxCollection.Click ( Sender: TObject );

var

clickedCBDescriptor, oneCBDescriptor: TCheckboxDescriptor;

c: integer;

begin

if handlingClick then exit;

handlingClick:=true;

clickedCBDescriptor:=FindSender ( Sender );

if clickedCBDescriptor.State = cbChecked then clickedCBDescriptor.State:=cbUnchecked

else begin

clickedCBDescriptor.State:=cbChecked;

for c:=0 to checkboxDescriptors.Count - 1 do begin

oneCBDescriptor:=checkboxDescriptors.Items[c];

if oneCBDescriptor <> clickedCBDescriptor then oneCBDescriptor.State:=cbUnchecked;

end;

end;

associatedDBEdit.DataSource.Edit;

associatedDBEdit.Text:=Value;

handlingClick:=false;

end;



procedure TPersonalityCBCollection.Click ( Sender: TObject );

var

clickedCB: TCheckbox;

clickedCBDescriptor, oneCBDescriptor: TCheckboxDescriptor;

c: integer;

begin

if handlingClick then exit;

handlingClick:=true;

clickedCB:=Sender as TCheckbox;

clickedCBDescriptor:=FindSender ( Sender );

if clickedCB.Name = 'CheckBox16' then

for c:=0 to checkboxDescriptors . Count - 1 do begin

oneCBDescriptor:=checkboxDescriptors.Items[c];

oneCBDescriptor.State:=cbUnchecked;

end

else case clickedCBDescriptor.State of

cbChecked: clickedCBDescriptor.State:=cbUnchecked;

else clickedCBDescriptor.State:=cbChecked;

end;

associatedDBEdit.DataSource.Edit;

associatedDBEdit.Text:=Value;

handlingClick:=false;

end;



function TPersonalityCBCollection.GetValue : string;

var

c, modulo, resultAsInt: integer;

oneCBDescriptor: TCheckboxDescriptor;

begin

resultAsInt:=0;

modulo:=1;

for c:=0 to checkboxDescriptors . Count - 2 do begin

if c > 0 then modulo:=modulo * 2;

oneCBDescriptor:=checkboxDescriptors.Items[c];

if oneCBDescriptor.checkbox.State = cbChecked then

resultAsInt:=resultAsInt + modulo;

end;

result:=IntToStr ( resultAsInt )

end;



function TCheckboxCollection.GetValue : string;

var

c: integer;

oneCBDescriptor: TCheckboxDescriptor;

begin

for c:=0 to checkboxDescriptors . Count - 1 do begin

oneCBDescriptor:=checkboxDescriptors.Items[c];

if oneCBDescriptor.checkbox.State = cbChecked then begin

if oneCBDescriptor.checkbox.Caption = 'N/A' then result:='0'

else result:=oneCBDescriptor.checkbox.Caption;

break

end

end

end;



procedure TPersonalityCBCollection.SetValue ( NewValue: string );

var

c, modulo, pattern: integer;

oneCBDescriptor: TCheckboxDescriptor;

begin

if NewValue = '' then exit;

if handlingClick then exit;

handlingClick:=true;

modulo:=1;

pattern:=StrToInt(NewValue);

for c:=0 to checkboxDescriptors . Count - 1 do begin

if c = 0 then modulo:=1 else modulo:=modulo * 2;

oneCBDescriptor:=checkboxDescriptors.Items[c];

if (pattern and modulo) <> 0 then oneCBDescriptor.State:=cbChecked

else oneCBDescriptor.State:=cbUnchecked;

end;

handlingClick:=false;

end;



procedure TCheckboxCollection.SetValue ( NewValue: string );

var

c: integer;

oneCBDescriptor: TCheckboxDescriptor;

begin

if NewValue = '' then exit;

if handlingClick then exit;

handlingClick:=true;

for c:=0 to checkboxDescriptors . Count - 1 do begin

oneCBDescriptor:=checkboxDescriptors.Items[c];

oneCBDescriptor.State:=cbUnchecked;

end;

c:=StrToInt(NewValue);

oneCBDescriptor:=checkboxDescriptors.Items[c];

oneCBDescriptor.State:=cbChecked;

handlingClick:=false;

end;



procedure TForm1.FormCreate(Sender: TObject);

begin

SeverityCBs := TCheckboxCollection . Create ( DBEdit1,

[ CheckBoxNA,CheckBox1, CheckBox2, CheckBox3, CheckBox4, CheckBox5, CheckBox6, CheckBox7, CheckBox8 ] );

PersonalityCBs:=TPersonalityCBCollection.Create ( DBEdit2,

[ CheckBox9, CheckBox10, CheckBox11, CheckBox12, CheckBox13, CheckBox14, CheckBox15, CheckBox16 ] );

Table1.Open

end;



procedure TForm1.CheckBoxNAClick(Sender: TObject);

begin

SeverityCBs.Click(Sender);

end;



procedure TForm1.DBEdit1Change(Sender: TObject);

begin

SeverityCBs.SetValue(DBEdit1.Text)

end;



procedure TForm1.CheckBox9Click(Sender: TObject);

begin

PersonalityCBs.Click(Sender);

end;



procedure TForm1.DBEdit2Change(Sender: TObject);

begin

PersonalityCBs.SetValue(DBEdit2.Text)

end;



end.


 

Share this article!

Follow us!

Find more helpful articles: