Reputation: 2321
I have an object that has some properties:
Obj.Big
Obj.Rotate
Obj.Paint
Obj.Lines
etc. They are all boolean type properties.
In my main procedure, I call another procedure:
procedure TMainForm.Create(Sender:TObject);
begin
SetParameter(BigCheckBox, Obj.Big);
SetParameter(RotateCheckBox, Obj.Rotate);
SetParameter(PaintCheckBox, Obj.Paint);
SetParameter(LinesCheckBox, Obj.Lines);
end;
The SetParameter
procedure goes like this:
procedure TMainForm.SetParameter(ACheckBox : TCheckBox; ABoolOption : Boolean);
begin
if(ACheckBox.Checked) and (ACheckBox.Enabled) then begin
ABoolOption := true;
end
else if(not ACheckBox.Checked) and (ACheckBox.Enabled) then begin
ABoolOption := false;
end;
end;
It accepts the checkbox object and the property of the passed object's boolean property as ABoolOption
. I cannot simple do LinesCheckBox.Checked := Obj.Lines
because I need to have a "do nothing" action when the checkbox is filled (they are all tri-state). When I run this, none of those object's parameters are changed. Why is this?
Upvotes: 0
Views: 140
Reputation: 596497
Your procedure does not do what you think it does. You are NOT passing the property itself, you are passing the CURRENT VALUE of the property instead. If you want to actually update the value of the property, you need to either do what Ken suggests, or use RTTI instead, eg:
uses
..., TypInfo;
procedure TMainForm.Create(Sender:TObject);
begin
SetBooleanParameter(BigCheckBox, Obj, 'Big');
SetBooleanParameter(RotateCheckBox, Obj, 'Rotate');
SetBooleanParameter(PaintCheckBox, Obj, 'Paint');
SetBooleanParameter(LinesCheckBox, Obj, 'Lines');
end;
procedure TMainForm.SetBooleanParameter(ACheckBox : TCheckBox; Obj: TObject; const PropName: String);
begin
if ACheckBox.Enabled then begin
// NOTE: this only works if the properties are declared as 'published'
SetOrdProp(Obj, PropName, Ord(ACheckBox.Checked));
end;
end;
Or, if you are using D2010+:
uses
..., Rtti;
procedure TMainForm.Create(Sender:TObject);
begin
SetBooleanParameter(BigCheckBox, Obj, 'Big');
SetBooleanParameter(RotateCheckBox, Obj, 'Rotate');
SetBooleanParameter(PaintCheckBox, Obj, 'Paint');
SetBooleanParameter(LinesCheckBox, Obj, 'Lines');
end;
procedure TMainForm.SetBooleanParameter(ACheckBox : TCheckBox; Obj: TObject; const PropName: String);
var
Ctx: TRttiContext;
begin
if ACheckBox.Enabled then
begin
// NOTE: this approach does not need the properties to be declared as 'published'
Ctx.GetType(Obj.ClassType).GetProperty(PropName).SetValue(Obj, TValue.From<Boolean>(ACheckBox.Checked));
end;
end;
Upvotes: 1
Reputation: 125708
You're not passing the property. You're passing the value of that property. IOW, your SetParameter
is receiving ACheckBox, True
or ACheckBox, False
, and therefore there's nothing for you to change. The better way might be to change your SetParameter
procedure to a function:
function TMainForm.SetBooleanValue(const ACheckBox: TCheckBox): Boolean;
begin
Result := (ACheckBox.Checked) and (ACheckBox.Enabled);
end;
And then use it like:
Obj.Big := SetBooleanValue(BigCheckbox);
Obj.Rotate := SetBooleanValue(RotateCheckBox);
Obj.Paint := SetBooleanValue(PaintCheckBox);
Obj.Lines := SetBooleanValue(LinesCheckBox);
If you need to allow for a third option, you should check it first before performing the call to SetBooleanValue
:
if not ThirdCondition then
Obj.Big := SetBooleanValue(BigCheckBox);
Upvotes: 5