Reputation: 750
I have created my own component which has a TFont in it along with appropriate properties.
The component has the following property in the Public declaration
property CaptionFont: TFont read fCaptionFont write SetCaptionFont;
The procedure SetCaptionFont looks like this
procedure TMyComponent.SetCaptionFont(value: TFont);
begin
fCaptionFont := value;
end;
I am trying to assign the Font name and Font size to my component with the following code:
MyComponent.CaptionFont.Name := fGlobalStandardFontName;
MyComponent.CaptionFont.Size := fGlobalStandardFontSize;
However, when putting a breakpoint at the line
MyComponent.CaptionFont.Name := fGlobalStandardFontName;
and then clicking the "Trace Into (F7)" debug button, the code jumps to the TFont code and completely ignores the SetCaptionFont procedure.
I am expecting the SetCaptionFont procedure to be called.
What's going on here?
Upvotes: 2
Views: 265
Reputation: 612794
The key to understanding this is placement of the assignment operator.
Property setters are called when you use the assignment operator on the property. The only way to make the property setter execute for your property is to write code of this form:
CaptionFont := ...;
You do not do this. Instead you write:
CaptionFont.Name := ...;
Here the getter for CaptionFont
is used, and then the setter for Name
.
That explains why the setter is not called.
Beyond that you implement the setter incorrectly. Your implementation is liable to leak the object that you created in the constructor, whose reference you hold in FCaptionFont
. When you assign to FCaptionFont
you lose track of that object.
The convention for properties that are classes, is to convert the action of setting the property into a call to Assign
. This makes the property have value semantics rather than reference. The properties value is copied. The setter therefore looks like this:
procedure TMyComponent.SetCaptionFont(Value: TFont);
begin
FCaptionFont.Assign(Value);
end;
Upvotes: 1
Reputation: 595377
SetCaptionFont()
is not called when assigning values to sub-properties, because you are not assigning anything to the CaptionFont
property itself.
Even if it were called, your SetCaptionFont()
is not implemented correctly anyway. You are taking ownership of the source TFont
and leaking your original TFont
. You need to use Assign()
instead to copy the source TFont
values into your existing TFont
.
To detect sub-property value changes (including from Assign()
), you need to assign on OnChange
event handler to your fCaptionFont
object, eg:
constructor TMyComponent.Create(AOwner: TComponent);
begin
inherited;
fCaptionFont := TFont.Create;
fCaptionFont.OnChange := CaptionFontChanged;
end;
procedure TMyComponent.SetCaptionFont(value: TFont);
begin
fCaptionFont.Assign(value);
end;
procedure TMyComponent.CaptionFontChanged(Sender: TObject);
begin
Invalidate;
end;
procedure TMyComponent.Paint;
begin
// use fCaptionFont as needed...
end;
Upvotes: 7