Having a nullable dataset field of a boolean type, how to display its NULL value as an unchecked state in a TDBCheckBox control descendant linked to this field. By default, TDBCheckBox displays the NULL value of the field as a grayed check box:

but I need it to be displayed as an unchecked state in my TDBCheckBox control descendant:

Modifying the original TDBCheckBox source code is not an option for me, nor I cannot override the TDBCheckBox.GetFieldState because it's a private method.
So, how can I display the NULL value as an unchecked state in my TDBCheckBox descendant ?
If your project is closed source I suggest taking a copy of DBCtrls, change that one line where it says Result := cbGrayed and add that explicitly to your project. The change will be in your entire application but did not change the original code.
However there is another way - actually a hack so be careful and I suggest putting a compiler directive preventing this to be compiled in a different Delphi version to require looking at that code again and making sure it works.
Here is the code that works in Delphi XE - it might look different in Delphi 6 but you will get the idea.
type
TDBCheckBoxHack = class(TCustomCheckBox)
private
FDataLink: TFieldDataLink;
FValueCheck: string;
FValueUncheck: string;
procedure DataChange(Sender: TObject);
function GetFieldState: TCheckBoxState;
function ValueMatch(const ValueList, Value: string): Boolean;
end;
I leave the implementation of these methods out because they are just a copy from the original copyrighted code. You have to change one or two lines in the GetFieldState method.
The trick is to create the same memory layout as the original TDBCheckBox so you can access the private fields - that is why this code should be used with care!
Then you assign the fixed DataChange method to the datalink:
TDBCheckBoxHack(DBCheckBox1).FDataLink.OnDataChange :=
TDBCheckBoxHack(DBCheckBox1).DataChange;
To make this easier to use you can use another trick of inheriting from the original TDBCheckBox and call your class exactly the same. You can then put this into some unit and add this after the DBCtrls in your uses. That causes calling your constructor for every TDBCheckBox you placed on your form without the need to use your own and register it to the IDE:
type
TDBCheckBox = class(DBCtrls.TDBCheckBox)
public
constructor Create(AOwner: TComponent); override;
end;
constructor TDBCheckBox.Create(AOwner: TComponent);
begin
inherited;
TDBCheckBoxHack(Self).FDataLink.OnDataChange := TDBCheckBoxHack(Self).DataChange;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With