Help with a Data Aware component I am making

I am trying to make a new data aware component for a project. I want a radio button. How it should work is I put them on a tGroupBox and they will only allow one to be on. The table has a lot of boolean fields and many can only have one picked at a time. Since the tdbradiogroup doesnot seem to allow me to assign each radio button to a seperate datafield, I opted to make a tDBRadioButton to work with my app.

I based the component on the tRadioButton and used parts of the logic from the tdbCheckBox to make it. Problems I seem to have...
1. hen I put it on a form and associate the datasource and fiend it generates an error saying the database is not in edit or insert mode. It should not do that at design time.

2. When the app is run and the dbradiobuttons are created and connect to the datasource, they try to write to the database. Well, you would think it should when one of the fields has to be fixed, but this won't happen since there is one record and all the fields are set to false. And in doing this it generates an error saying not in edit or insert mode.

Can someone take a look at this bad little complonent and offer some help?

Many thanks,
David

Since changing one radio button will call all the buttons to update, I alwa
unit DataAware;
 
interface
uses
  Windows, Messages, Classes, Graphics, Controls, StdCtrls,
  Forms, DB, DBCtrls, DBTables, Buttons, sysutils;
 
type
  { TDBRadioButton }
  TDBRadioButton = class(TRadioButton)
  private
    FDataLink: TFieldDataLink;
    FValueCheck: string;
    FValueUncheck: string;
    function GetDataField: string;
    function GetField: TField;
    function GetDataSource: TDataSource;
    function GetReadOnly: Boolean;
    function ValueMatch(const ValueList, Value: string): Boolean;
    function GetFieldState: boolean;
 
    procedure SetDataField(const Value: string);
    procedure SetDataSource(Value: TDataSource);
    procedure DataChange(Sender: TObject);
    procedure UpdateData(Sender: TObject);
    procedure SetReadOnly(Value: Boolean);
    procedure SetValueCheck(const Value: string);
    procedure SetValueUncheck(const Value: string);
    procedure CMExit(var Message: TCMExit); message CM_EXIT;
    procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
 
  protected
    procedure SetChecked(Value: Boolean); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Field: TField read GetField;
  published
    property DataField: string read GetDataField write SetDataField;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
 
  end;
 
procedure Register;
 
implementation
constructor TDBRadioButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDataLink := TFieldDataLink.Create;
  FDataLink.Control := Self;
  FDataLink.OnDataChange := DataChange;
  FDataLink.OnUpdateData := UpdateData;
end;
 
destructor TDBRadioButton.Destroy;
begin
  FDataLink.Free;
  FDataLink := nil;
  inherited Destroy;
end;
 
function TDBRadioButton.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;
 
procedure TDBRadioButton.SetDataSource(Value: TDataSource);
begin
  if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
    FDataLink.DataSource := Value;
  if Value <> nil then Value.FreeNotification(Self);
end;
 
function TDBRadioButton.GetDataField: string;
begin
  Result := FDataLink.FieldName;
end;
 
procedure TDBRadioButton.SetDataField(const Value: string);
begin
  FDataLink.FieldName := Value;
end;
 
 
function TDBRadioButton.GetReadOnly: Boolean;
begin
  Result := FDataLink.ReadOnly;
end;
 
procedure TDBRadioButton.SetReadOnly(Value: Boolean);
begin
  FDataLink.ReadOnly := Value;
end;
 
function TDBRadioButton.GetField: TField;
begin
end;
 
function TDBRadioButton.GetFieldState: boolean;
begin
  if FDatalink.Field <> nil then
    if FDataLink.Field.IsNull then
      Result := false
    else if (FDataLink.Field.DataType = ftBoolean) then
      if FDataLink.Field.AsBoolean then
        Result := true
      else
        Result := false
    else
    begin
      Result := false;
      Text := FDataLink.Field.Text;
      if ValueMatch(FValueCheck, Text) then Result := true else
        if ValueMatch(FValueUncheck, Text) then Result := false;
    end
  else
    Result := false;
end;
 
function TDBRadioButton.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 TDBRadioButton.SetValueCheck(const Value: string);
begin
  FValueCheck := Value;
  DataChange(Self);
end;
 
procedure TDBRadioButton.SetValueUncheck(const Value: string);
begin
  FValueUncheck := Value;
  DataChange(Self);
end;
 
procedure TDBRadioButton.CMExit(var Message: TCMExit);
begin
  try
    FDataLink.UpdateRecord;
  except
    SetFocus;
    raise;
  end;
  inherited;
end;
 
procedure TDBRadioButton.CMGetDataLink(var Message: TMessage);
begin
  Message.Result := Integer(FDataLink);
end;
 
 
procedure TDBRadioButton.UpdateData(Sender: TObject);
var
  Pos: Integer;
  S: string;
begin
   if FDataLink.Field = nil then Exit;
 
   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;
 
 
procedure TDBRadioButton.DataChange(Sender: TObject);
begin
   if FDatalink.Field <> nil then
   	checked := GetFieldState;
end;
 
procedure TDBRadioButton.SetChecked(Value: Boolean);
Begin
	if Value=Checked then exit;
   inherited SetChecked(value);
   UpdateData(self);
   DataChange(Self);
End;
{---------------------------------------------------------------------}
 
{ Register the components }
procedure Register;
begin
  RegisterComponents('My Data Awares', [TDBRadioButton]);
end;
end.

Open in new window

LVL 2
rhawkAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

SteveBayCommented:
I know this will not sound like much help but..

I would have started with a data aware component like TDBCheckBox and overridden the paint routines to make it look like a radio button rather than try to make a TRadioButton data aware.  It just seems like less work to me. That is just my "off the cuff" opinion. By no means does that mean that your approach is wrong.

Anyway when I get more time I will try to get a look at your component and see if I can tell you whats happening.
0
rhawkAuthor Commented:
Hi SteveBay,
Not that your solution is not a good idea, but my knowledge on pait routines would be about .001%, so it would be harder in the end, for me. If you can help me through that way, or my way, I would be very happy for the help. :)
0
rhawkAuthor Commented:
Actually thinking a bit, the check box is not a bad idea. It allows for values or boolean based on the check or not, and I would like the option of using this on a boolean field, numeric or string. :)
0
Cloud Class® Course: CompTIA Healthcare IT Tech

This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

SteveBayCommented:
I think I have found the answer to your behavior. The problem lies in the SetChecked routine. SetCheck can be called at design time and will call UpdateData which in turn will try to update the table value causing the insert/edit mode error. SetChecked is actually being called when the table is attached to the component and the radio button is toggled by the field value and at run time SetChecked is being called when you scroll the dataset. The dataset updates the control and then the control tries to update the dataset.  

You can fix this behavior by calling the inherited routine first

procedure TDBRadioButton.SetChecked(Value: Boolean);
Begin
   inherited SetChecked(value);
   if Value=Checked then exit;
   UpdateData(self);
   DataChange(Self);
End;

This way the Radio button will always reflect the state of the Field in the DB.

Remember you can not toggle a radio to the unchecked state by clicking it. You must click one of its siblings to checked state to uncheck a radio button.

This does beg the more philosophical question of can/should you really use standalone radio buttons as data-aware components.  By definition every radio button should have (a) sibling radio button(s) that represents the other choice(s) whereas a CheckBox is either checked or not (let's forget about grayed for the moment). The only way to truly use radio buttons in this fashion would be to have a radio group of two, one for True and one for False. The DBRadioGroup would require some special handling for this as it is really design to work with character fields.

My suggestion is to work with the DBCheckBox as it was designed specifically for this purpose. If you would still like it to look like a radio button I think that I can help with that as well.  
0
SteveBayCommented:
I spoke too soon.

>> I would have started with a data aware component like TDBCheckBox and overridden the paint routines.

This is definitely a more difficult option. TDBCheckBox is a descendant of TWinContol and therefore just a wrapper around a control that Win32 already knows how to draw. There is no canvas and there is no paint to override.

That means using the alternative of starting with a TCustomControl and then adding all of the checkbox behavior and data awareness. Way more work! :o
0
rhawkAuthor Commented:
On your 2nd to last post, I will be placing many of the RadioButtons on the Groupbox, and the behavior of only allowing one to select is correct. In order to allow all to be cleared, I will add a TRadioButton (non-Dataaware) stating "none" next to it. So when they hit it all the others uncheck.

One of the tabs in this application deals with USPS shipping options... So imagine a group box that has the following radio buttons:
( ) Delivery Confirmation
( ) Signature Confirmation
( ) Signature Confirmation only by recipient
( ) No Confirmation

The table (which I did not design) has seperate boolean fields for the first 3 choices. Any ONE can be picked or none picked. So the last option is a standard radio button in the group box, and by the behavior of the group box, it will unselect the others if this one is selected, thus setting the database fields all to false.

Does this make a bit more sense now?

I will try your changes later this morning and see if that solves the issues I am having.
Since I do not want the  design time to affect the table records, is there a way I can ask if the component is in a design layout and then just exit the update procedure? Is that something I need worry about with your changes?

Thanks for the help to date.
0
developmentguruPresidentCommented:
Unfortunately what you are asking is a fairly advanced control for someone who has not done custom controls before.  You normally start with a functional non-data awar control, then descend from it to create the data aware version.  In this case the recommendation would be to create 4 new classes.

TCustomControl
  TCustomMyNewRadioButton
    TMyNewRadioButton
    TCustomDBMyNewRadioButton
      TDBMyNewReadioButton

the indentation shows the hierarchy.  the custom versions are created to hide all functionality so that you expose what you want to in the full version.  This allows people to descend from custom and only expose what they want to expose.

  The first step in creating the non - db aware version is to override paint and get it to look the way you want.  Then implement the checked property.  when the value of checked changes you need to call invalidate so it will repaint.  Then change the paint routine so it can change how it paints based on the value of checked.

  Once you have this working you need to implement a mechanism that allows you to make individual controls act as though they are one control.  The easiest way I have done this is to use messages.  Using the functions GetParentForm and Broadcast you can broadcast a message that you create such as shown in the example from TSpeedButton code.

procedure TSpeedButton.UpdateExclusive;
var
  Msg: TMessage;
begin
  if (FGroupIndex <> 0) and (Parent <> nil) then
  begin
    Msg.Msg := CM_BUTTONPRESSED; //your message here
    Msg.WParam := FGroupIndex; //I would use the control the is getting focus here
    Msg.LParam := Longint(Self); //I would use the Tag or other group identifier here
    Msg.Result := 0;
    Parent.Broadcast(Msg);
  end;
end;

In the message response for your class you would have code something like this

  if Tag = Message.LParam then
    if Self <> Message.WParam then
     Checked := false;

of course the broadcast would come from setting checked to true on one of the controls.

I do not have time to do the controls myself, good luck.
0
rhawkAuthor Commented:
Will, I just tried it. I still get the error at design time if I activate the table. When I run the program it does initially reflect the database fields (what is selected) but it does not seem to update the field now. I can pick any option and save and it does not change the database, yet some other db controls (a check box and text fields) do update the tabe.
0
SteveBayCommented:
My test revealed the same problem. Chancing the button state does not update the field value because the field value updated the button state first.

My short term suggestion is to handle this with non-data-aware radio buttons and set the field value in the OnClick event
0
diniludCommented:
Try like this


procedure TDBRadioButton.UpdateData(Sender: TObject);
var
  Pos: Integer;
  S: string;
begin
   if FDataLink.Field = nil then Exit;

   if FDataLink.Field.DataType = ftBoolean then
   begin
       FDataLink.Field.DataSet.Edit;
       FDataLink.Field.AsBoolean := Checked;
       FDataLink.Field.DataSet.Post;
   end
   else begin
        if Checked then S := FValueCheck else S := FValueUncheck;
        Pos := 1;
        FDataLink.Field.DataSet.Edit;
        FDataLink.Field.Text := ExtractFieldName(S, Pos);
        FDataLink.Field.DataSet.Post;
   end;
end;


0
diniludCommented:
procedure TDBRadioButton.SetChecked(Value: Boolean);
Begin
        if Value=Checked then exit;
   inherited SetChecked(value);
   if not (csDesigning in ComponentState) then
   begin
     UpdateData(self);
     DataChange(Self);
   end;
End;
0
rhawkAuthor Commented:
developmentguru, thanks for your response. Some of that is a bit beyond me right now. The only components I have made thus far are new string grids and such. Dealing with messages in Windows is something I have yet to try.
0
rhawkAuthor Commented:
dinilud,
Thanks for the help. If I put in your code other problems happen. When the form is created I got a "Dataset not in edit or insert mode" and each time I check one of the check boxes I get that same error like 10 times (I am assuming clicking on one rb makes the code try to update the table and I get the error. Then the Group Box attempts to change all the other radio button states, each in turn generating that error again). What did I miss that is not putting the dataset in the mode needed, and since it is the same dataset all the standard db controls are using on the form, why can I edit a field fine, then try the radio button and I again get the not in edit or insert error, when the other db control has clearly edited a field? Weird.
0
SteveBayCommented:
this seems to work better:

procedure TDBRadioButton.UpdateData(Sender: TObject);
var
  Pos: Integer;
  S: string;
begin
   if FDataLink.Field = nil then Exit;

   if  not (FDataLink.DataSet.State in [dsEdit, dsInsert]) then
            FDataLink.DataSet.Edit;

  if FDataLink.Field.DataType = ftBoolean then
       begin
       FDataLink.Field.AsBoolean := Checked;
       end
  else begin
       if Checked then S := FValueCheck else S := FValueUncheck;
            Pos := 1;
       FDataLink.Field.Text := ExtractFieldName(S, Pos);
       end;
end;

0
SteveBayCommented:
Still not perfect though.  Putting the dataset in Edit fires another UpdateData thereby ignoring the first state change of the button.
0
SteveBayCommented:
This works for me.
procedure TDBRadioButton.UpdateData(Sender: TObject);
var
  Pos: Integer;
  S: string;
begin
   if (FDataLink.Field = nil) then Exit;
 
  if FDataLink.Field.DataType = ftBoolean then
	 begin
	 FDataLink.Field.AsBoolean := Checked;
	 end
  else begin
	 if Checked then S := FValueCheck else S := FValueUncheck;
		Pos := 1;
	 FDataLink.Field.Text := ExtractFieldName(S, Pos);
	 end;
end;
 
 
procedure TDBRadioButton.DataChange(Sender: TObject);
begin
   if FDatalink.Field <> nil then
	begin
	if  not (FDataLink.DataSet.State in [dsEdit, dsInsert]) then
		FDataLink.DataSet.Edit;
 
	checked := GetFieldState;
	end;
end;
 
procedure TDBRadioButton.SetChecked(Value: Boolean);
Begin
   if Value=Checked then exit;
   inherited SetChecked(value);
   if not (csDesigning in ComponentState) then
   begin
     UpdateData(self);
     DataChange(Self);
   end;
End;

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
SteveBayCommented:
While it works, it is still not perfect. This code will set the table in the state of edit when the table sets the radio button state. The trick here is to only sret hte table in edit when a button has been changed by the user.
0
rhawkAuthor Commented:
SteveBay, Wow, that worked perfect. Just one last thing.... If I activate my tadotable so I can see the record at design time as well, I still get that error there. Any idea how to check if it is being run as an exe vs. in Delphi 2007 design time? If I can test for that I can stop it from trying to update the database at design time, so it would just display it.
0
rhawkAuthor Commented:
Okay, looking at the code now for the 1st time, you do check for component state. that must be failing if I get the error on an active connect. Hmmm.
0
rhawkAuthor Commented:
Stupid me, I have been changing the source and using it in the compile, I have not recompiled the component itself. .... Let me do that.
0
rhawkAuthor Commented:
SteveBay, Excellent! Thank you so very much! I plan to tweak the component a bit so it will work with boolean fields as well as integer and strings (different value for checked and unchecked) so it is a bit more rounded and usable to me later for more stuff. Thank you so very much for your help and everyone who chimed in to help as well!

David
0
SteveBayCommented:
Thanks for accepting my answer though I am not fully satified with my approach.
First, here is a more correct way to this:

procedure TDBRadioButton.DataChange(Sender: TObject);
begin
   if FDatalink.Field <> nil then
      begin
      if (not (FDataLink.DataSet.State in dsEditModes )) then
            FDataLink.Edit;
      checked := GetFieldState;
      end;
end;

Second, I still don't like the fact that the FdataLink.Edit is called when the table is scrolled even though the user did not initiate a change. I will try to solve this problem as well.
0
rhawkAuthor Commented:
I will of course be delighted with improvements. :)
0
SteveBayCommented:
I knew I would figure this out eventually...
This is the most correct way to do this that I have found so far. Note: we are not intersted in the CM_Exit message we're actually most interested in the CM_Enter message.  This is how we know that the user has made and edit. This way the Table is only placed in edit when the user changes the state of the control.

Now I need to get back to my real work. :D
unit DataAware;
 
interface
uses
  Windows, Messages, Classes, Graphics, Controls, StdCtrls,
  Forms, DB, DBCtrls, DBTables, Buttons, sysutils, DBConsts, CodeSiteLogging;
type
  { TDBRadioButton }
  TDBRadioButton = class(TRadioButton)
  private
    FDataLink: TFieldDataLink;
    FValueCheck: string;
    FValueUncheck: string;
    InDataUpdate : Boolean;
    function GetDataField: string;
    function GetField: TField;
    function GetDataSource: TDataSource;
    function GetReadOnly: Boolean;
    function ValueMatch(const ValueList, Value: string): Boolean;
    function GetFieldState: boolean;
 
    procedure SetDataField(const Value: string);
    procedure SetDataSource(Value: TDataSource);
    procedure DataChange(Sender: TObject);
    procedure UpdateData(Sender: TObject);
    procedure SetReadOnly(Value: Boolean);
    procedure SetValueCheck(const Value: string);
    procedure SetValueUncheck(const Value: string);
    procedure CMGetDataLink(var Message: TMessage); message CM_GETDATALINK;
    procedure CMEnter(var Message: TMessage); message CM_ENTER;
 
  protected
	ClickedByUser : Boolean;
    procedure SetChecked(Value: Boolean); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property Field: TField read GetField;
	procedure Click; override;
  published
    property DataField: string read GetDataField write SetDataField;
    property DataSource: TDataSource read GetDataSource write SetDataSource;
    property ReadOnly: Boolean read GetReadOnly write SetReadOnly default False;
 
  end;
 
procedure Register;
 
implementation
constructor TDBRadioButton.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csReplicatable];
 
	ClickedByUser := False;
 
  //State := cbUnchecked;
  FValueCheck := STextTrue;
  FValueUncheck := STextFalse;
 
 
  FDataLink := TFieldDataLink.Create;
  FDataLink.Control := Self;
  FDataLink.OnDataChange := DataChange;
  FDataLink.OnUpdateData := UpdateData;
end;
 
destructor TDBRadioButton.Destroy;
begin
  FDataLink.Free;
  FDataLink := nil;
  inherited Destroy;
end;
 
function TDBRadioButton.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;
 
procedure TDBRadioButton.SetDataSource(Value: TDataSource);
begin
  if not (FDataLink.DataSourceFixed and (csLoading in ComponentState)) then
    FDataLink.DataSource := Value;
  if Value <> nil then Value.FreeNotification(Self);
end;
 
function TDBRadioButton.GetDataField: string;
begin
  Result := FDataLink.FieldName;
end;
 
procedure TDBRadioButton.SetDataField(const Value: string);
begin
  FDataLink.FieldName := Value;
end;
 
 
function TDBRadioButton.GetReadOnly: Boolean;
begin
  Result := FDataLink.ReadOnly;
end;
 
procedure TDBRadioButton.SetReadOnly(Value: Boolean);
begin
  FDataLink.ReadOnly := Value;
end;
 
function TDBRadioButton.GetField: TField;
begin
  Result := FDataLink.Field;
end;
 
function TDBRadioButton.GetFieldState: boolean;
begin
  if FDatalink.Field <> nil then
    if FDataLink.Field.IsNull then
	 Result := false
    else if (FDataLink.Field.DataType = ftBoolean) then
	 if FDataLink.Field.AsBoolean then
	   Result := true
	 else
	   Result := false
    else
    begin
	 Result := false;
	 Text := FDataLink.Field.Text;
	 if ValueMatch(FValueCheck, Text) then Result := true else
	   if ValueMatch(FValueUncheck, Text) then Result := false;
    end
  else
    Result := false;
end;
 
function TDBRadioButton.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 TDBRadioButton.SetValueCheck(const Value: string);
begin
  FValueCheck := Value;
  DataChange(Self);
end;
 
procedure TDBRadioButton.SetValueUncheck(const Value: string);
begin
  FValueUncheck := Value;
  DataChange(Self);
end;
 
procedure TDBRadioButton.CMEnter(var Message: TMessage);
begin
  try
	if (not (FDataLink.DataSet.State in dsEditModes )) then
		FDataLink.Edit;
  except
    SetFocus;
    raise;
  end;
  inherited;
 
end;
 
 
procedure TDBRadioButton.CMGetDataLink(var Message: TMessage);
begin
  Message.Result := Integer(FDataLink);
end;
 
procedure TDBRadioButton.UpdateData(Sender: TObject);
var
  Pos: Integer;
  S: string;
begin
   if (FDataLink.Field = nil) then Exit;
   if FDataLink.Field.DataType = ftBoolean then
	   begin
	   FDataLink.Field.AsBoolean := Checked;
	   end
   else begin
	   if Checked then S := FValueCheck else S := FValueUncheck;
		  Pos := 1;
	   FDataLink.Field.Text := ExtractFieldName(S, Pos);
	   end;
end;
 
procedure TDBRadioButton.Click;
begin
	ClickedByUser := True;
	inherited;
end;
 
procedure TDBRadioButton.DataChange(Sender: TObject);
begin
   if FDatalink.Field <> nil then
	begin
	checked := GetFieldState;
	end;
end;
 
procedure TDBRadioButton.SetChecked(Value: Boolean);
Begin
   if Value=Checked then exit;
   inherited SetChecked(value);
   if not (csDesigning in ComponentState) then
   begin
	if FDataLink.Editing then
		begin
		UpdateData(self);
		DataChange(Self);
		end;
   end;
End;
 
{ Register the components }
procedure Register;
begin
  RegisterComponents('My Data Awares', [TDBRadioButton]);
end;
 
end.

Open in new window

0
rhawkAuthor Commented:
New minor issue.... Now testing the latest and if I place a stansard nondata aware radio button on the form as well and make it's caption "none", it does of course clear all the dbRadioButtons on the form, as expected. But the clearing does not update the database. Each of the boolean fields in the table should have been set to false. Any idea why not?
0
SteveBayCommented:
Yes, because the DBRadiobuttons only update the data when they process a CM_ENTER message. I suggest that your non-data aware radio button should set all of the fields in the table to false and let that change your buttons rather changing the state of the buttons.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.