We are working on creating custom component in firemonkey on Delphi Xe2 platform. I am creating published property with firemonkey custom component. I have set default value such as Boolean, custom type, but I am setting default integer value. I am using class TControl1 = class(TControl).
Published
Property Test : Integer read FTest write Set Test default 10;
On component viewer my custom component shows 0 default.Sorry for my bad english.
Please anyone help me
If I remember correctly, default directive does not set your private member, FTest. You have to initialize it in your component's constructor like this:
TControl1 = class(TControl)
private
FTest: Integer;
procedure SetTest(Value: Integer);
public
constructor Create(AOwner: TComponent); override;
published
property Test: Integer read FTest write SetTest default 10;
end;
.
.
.
constructor TControl1.Create;
begin
inherited;
FTest := 10;
end;
Specifying the default property value does not assign that value to the property at runtime. All it does is control how the property is stored. If the property's value is equal to the default when the property is stored, then the VCL streaming framework omits the property.
The documentation says it like this:
When you declare a property, you can specify a default value for it. The VCL uses the default value to determine whether to store the property in a form file. If you do not specify a default value for a property, the VCL always stores the property.
...
Declaring a default value does not set the property to that value. The component's constructor method should initialize property values when appropriate. However, since objects always initialize their fields to 0, it is not strictly necessary for the constructor to set integer properties to 0, string properties to null, or Boolean properties to False.
In other words, you must initialise the property in the component's constructor, in addition to setting the default value. And the onus is on you to ensure that you initialise it to the same value as you specified as the default.
I have personally always found the duplication inherent in the design to be somewhat frustrating. The designers have succeeded in building into the language a violation of the DRY principle. The very fact that you have asked this question illustrates the weakness of the design. Having specified the default value you are surprised that the compiler appears to ignore you and demands that you set it again.
Related
I would like to use attributes to read/write in property values to/from the registry.
All of the examples I have looked use a Load/Save function to loop over all the properties and examine the attributes. Instead of having a Load/Save routine I would like to read the value from the registry when the property is read or written. However, I can't figure out how to find out the name of the current property in the Read method.
I know I could have a one line getter/setter for my properties that pass in the correct string values to the Read/Write methods. I was hoping I could use attributes. Then when I define simple classes with the properties I want to save and restore. I would not need to write have any code for those classes. Everything would be dealt with the in the base class.
It could be that this is not possible.
I'm taking this example from Robert Love as my starting point:
http://robstechcorner.blogspot.de/2009/10/ini-persistence-rtti-way.html
type
RegValueAttribute = class(TCustomAttribute)
private
FName: string;
FDefaultValue: string;
published
constructor Create(const aName : string;const aDefaultValue : String = '');
property Name : string read FName write FName;
property DefaultValue : string read FDefaultValue write FDefaultValue;
end;
TRegBaseClass = class
protected
procedure WriteString(AValue: string);
function ReadString: string;
end;
TMyRegClass = class(TRegBaseClass)
public
[RegValueAttribute('MySavedProperty', 'DefaultValue')]
property MySavedProperty: string read ReadString write WriteString;
end;
///////////////////////////////////////////
function TRegBaseClass.ReadString: string;
begin
// ?? Is there any way to get the attributes for the property
// that got me here.
end;
procedure TRegBaseClass.ReadString(AValue: string);
begin
// ?? Is there any way to get the attributes for the property
// that got me here.
end;
A given getter/setter can be used for multiple properties. The only way for a getter/setter to know which property is the caller is to use the index specifier on the property declaration, which then gets passed to the getter/setter as an input parameter. The getter/setter can then use RTTI to loop through the owning object's properties looking for the property with the specified index, and then use the attributes of that property as needed.
The relationship is that the the property has associated with it a getter and a setter. The getter/setter itself has no a priori knowledge that it is being used as a getter/setter. For instance, multiple properties could use the same getter/setter.
So the best you can do, as it stands, is to iterate over all the properties of the type, using RTTI, looking for the currently executing method as a property getter/setter. That does not sound like much fun.
I suspect that the best attribute based approach involves attaching attributes to the getter/setter methods.
When I'm building a custom component, I may implement published persistent properties. For example...
type
TMyComponent = class(TComponent)
private
FMyPersistent: TMyPersistent;
...
public
...
published
property MyPersistent: TMyPersistent read FMyPersistent write SetMyPersistent;
...
end;
Note that the procedure SetMyPersistent is not here yet, that's where the next step comes in. I right-click this object and select "Complete Class at Cursor" (or Shift + Control + C) to invoke the code completion. When it automatically creates this property setter, it automatically puts the assignment code in...
procedure TMyComponent.SetMyPersistent(const Value: TMyPersistent);
begin
FMyPersistent := Value;
end;
Now it's nice that it went ahead and completed this assignment for me. However, in normal cases, I've always grown accustomed to using...
procedure TMyComponent.SetMyPersistent(const Value: TMyPersistent);
begin
FMyPersistent.Assign(Value);
end;
In cases where the property is a type such as String or Integer, then a direct assignment is the proper way to do it. But when implementing a published property of a TPersistent, isn't it the correct method using TPersistent.Assign?
What's the essential difference between using these two assignment mechanisms? Because if using TPersistent.Assign is the appropriate thing to do, then the code completion has a slight flaw - that is, assuming that FMyPersistent := Value is considered "wrong".
Call Assign. That's why you have a property setter in the first place. If you were to directly overwrite the field, you wouldn't need a setter. Overwriting it would leak the original object you created in the constructor. You'd also notice access violations in the IDE when you modified the property in the Object Inspector.
Code completion puts the same code in every setter it creates. For properties that have additional work to do before ultimately storing the value in a field, so the field-storage statement is correct. The IDE doesn't know what you really want.
The question you should be asking yourself is - who owns the objects involved? If your component creates and owns FMyPersistent then use FMyPersistent.Assign(Value) to copy values from Value into FPersistent. If FMyPersistent merely points at an external object that someone else owns then use FMyPersistent := Value instead.
Can we say :
type
TPerson = class
private
pName : string;
public
property Name : string read pName write pName;
end;
Is equal with :
type
TPerson = class
private
pName : string;
public
procedure SetName(val: string);
function GetName:String;
end;
//{... implementing SetName And GetName...}
??
Please explain to me where we need to use "property" and where not. Tnx
It's all about the design of the class. Technically, 'everything' you can do with properties, you can do without them, but the code will not be as elegant. Good design also makes the classes easier to use, and reduces the risk of making mistakes.
First, your comparing
TPerson = class
private
FName: string;
public
property Name: string read FName write FName;
end;
to
TPerson = class
private
FName: string;
public
procedure SetName(const Name: string);
function GetName: string;
end;
isn't quite fair. Indeed, in the first case, you have no chance of doing something when the value is set (or read). So a more appropriate comparison would be to compare the latter code to
TPerson = class
private
FName: string;
procedure SetName(const Name: string);
function GetName: string;
public
property Name: string read GetName write SetName;
end;
For instance, if you write a control, you often need to invalidate (basically, repaint) the control when you alter a property, say, the 'Sweater colour' of the TPerson. For instance,
TPerson = class
private
FSweaterColor: string;
procedure SetSweaterColor(const Value: TColor);
public
property SweaterColor: TColor read FSweaterColor write SetSweaterColor;
end;
...
implementation
procedure TPerson.SetSweaterColor(const Value: TColor);
begin
if FSweaterColor <> Value then
begin
FSweaterColor := Value;
Invalidate; // causes a repaint of the control
end;
end;
Anyhow, what's the point of properties? Well, the point, basically, is to make a nice interface of the class: It should be easy to use for someone not interested in the details of its implementation. By using properties, you can achieve this goal. Indeed, to read the current colour of the sweater, you just read Anna.SweaterColor, and to set it, you just Anna.SweaterColor := clRed. You don't know if this simply sets a variable or causes a procedure to run, and you don't care. As far as you are concerned, a TPerson object simply has a readable and setable property called SweaterColor.
You can also create properties that are read-only (no write) or write-only (no read). But no matter how you implement the read and write (if at all) of a property, the property will look the same from the class user's point of view. He need not remember to use SetSweaterColor or GetSweaterColor (in fact, they are private and not accessible to him), but only the SweaterColor property.
This also hints at another benefit of using properties. Public and published properties are visible to the users of the class, while the private members are not (like the field FSweaterColor and the SetSweaterColor procedure). This is good. Because now you know that the only way for the class user to change the sweater colour of a person is to use the SweaterColor property, which guaranteed will repaint the control. If the FSweaterColor variable were public, the user of the class might set this and wonder, "why doesn't anything happen when I change the sweater color?" Of course, you don't need properties to get this benefit: a private FSweaterColor field and public GetSweaterColor and SetSweaterColor would do just as well, but then you'd need to write a GetSweaterColor function even though no processing is required to get the color. Also, the user of the class need to learn to use two identifiers instead of one.
More concretely, if you use the Delphi IDE to program, you will see that the published property (-y+ies) will show up in the Object Inspector, where you are allowed to read/change them (if applicable). How would that be possible if it weren't for properties?
All this being said, sometimes you don't use properties even though you could. For instance, if you have a read-only 'property', you might go for a single public GetSomething function instead of a read-only property. After all, that would save you some coding. Similarly, if you have a write-only property, you could go with a single public SetSomething procedure, which will also save you code. Finally, if you have a read/write property that requires no processing either way (neither to get nor to set), you could simply use a public variable!
So, after all, you need to decide on a good design of your class on a class-by-class basis. I guess the short version of my overly long answer is similar to David's comment:
Use whichever you prefer, whichever is more convenient.
Properties is a nice piece of syntactic sugar. They are equivalent to a pair of getEnabled and setEnabled Methods, but most programmers (and programming languages) prefer properties instead. For example there are less entries in the code-completion window.
Furthermore they separate "variable like" stuff (so the data, the object is supposed to work with) from the methods that work with the data.
Properties are not limited to components, they are very useful otherwise. You can define a public interface with a property and implement some validation logic afterwards. (Not possible with a public field) But you nee only two lines of code for a simple property, compared to 8 lines for the methods.
More important for the object inspector is the published keyword, only published properties are displayed in the OI.
No. These two codes are NOT equal.
We use property when we implement the TPerson class as a component, customizable in Delphi's Object Inspector. Take a look at the TButton class, for example. All the things you can alter in the Object Inspector (Caption, Width, Name, etc.) are marked in the source code with the property keyword.
If you create a class that will be used in your program but not as a component, you don't use the property keyword.
TMS's FormSize component saves aForm's size and position in an .ini file. This file's path is stored in the component's SaveName property. I would like to assign FormSize.SaveName to a file in the user's AppData folder. I can find the AppData path in my source code.
Does anyone know where (in my code) I assign the AppData path to FormSize.SaveName? I am thinking the FormSize component is created, and a default SaveName initialized, BEFORE aForm is created. In other words, FormSize loads the config file BEFORE aForm's FormCreate event fires; assigning a value to FormSize.SaveName during aForm.FormCreate is too late.
Thanks, as always.
The adjustment of the form is done in the Loaded method of TFormSize, not when you change the SaveName property (although it has been read from the DFM before).
If you set the properties SavePosition and SaveSize to false during designtime, there will nothing be loaded at runtime. In that case you can manually load and save the settings at a convenient place in your code by calling LoadFormSettings and SaveFormSettings.
I'd expect SaveName to be stored in the .dfm file, so it should be assigned to the component at load up.
If you want to determine the save name in code, it should probably be early in the cycle. I just checked a few possibilities:
In the form's constructor (override), before the call to inherited;
in the form's constructor (override), after the call to inherited;
in the form's FormCreate event handler;
in the form's Loaded procedure (override), before the call to inherited and
in the form's Loaded procedure (override), after the call to inherited.
Possibilities 4 and 5 worked as expected. 3 and 2 did nothing and 1 caused an AV. So David's suggestion seems to be fine.
"assigning a value to FormSize.SaveName during aForm.FormCreate is too
late."
I had a similar requirement to modify a component's property owned by a module. The standard "Create" event was too late given the loaded property was already in effect.
Properties persisted in the DFM are assigned (or cached) during the call to the protected virtual ReadState procedure. Conventionally, cached properties are activated during the protected virtual call to Loaded. Both ReadState and Loaded can be overridden.
In my case, I wanted to make sure TADOConnection's Connected property was false in the release build. During development, the component's property is normally true given design needs of dependent data sets.
It was a pain having to set the property to false prior to checking-in the code for subsequent builds/deployment. So instead, I overrode the Loaded method and hacked the streamed property value to false.
interface
type
TMyDataModule = class(TDataModule)
MyAdoConnection: TADOConnection;
protected
procedure Loaded; override;
end;
implementation
type
TADOConnectionHack = class(TADOConnection) end;
procedure TMyDataModule.Loaded;
begin
TADOConnectionHack(MyAdoConnection).StreamedConnected := False;
inherited Loaded;
end;
Is it possible to declare a property in an interface without declaring the get- and set-methods for it? Something like:
IValue = interface
property value: double;
end;
I want to state that the implementor should have a property called value, returning a double, but I really don't care if it returns a private field or the result from a function.
If it is possible, is it possible to declare it read/write or read-only?
No. Interfaces are implemented as function tables (basically a simple virtual method table) and the compiler needs to know there's a function to map the property onto. You can declare a property on an interface, but it has to have functions as getter/setter values, not fields. You can make it read-only or write-only, though.
When working with properties in an interface, think of the property as a shortcut to the reader/writer. Only one is required to satisfy the shortcut...otherwise it doesn't point to anything.