If you need to store additional data in a component, you can create new fields or new properties. If you create a new field, you will be able to work with the data stored in the field, but you won't be able to control how the field is accessed. However, if you create a new property, you will be able to control how the property's value is accessed and modified.
To create a new property, do the following:
Create a new field to hold the property's value (usually in the private section).
Define the property's name, type, and read and write access using the reserved word property (usually in the public or published sections).
Here's how to declare a simple property:
property PropertyName: Type read FieldName write FieldName;
The read and write specifiers enable you to define how the underlying field is accessed. The field can be accessed directly if you specify the field's name or through a method if you specify a valid method in either the read or the write specifier (you'll see this shortly).
Here's how to add a simple string property to the TSimple component:
type TSimple = class(TComponent) private { Private declarations } FMyString: string; protected { Protected declarations } public { Public declarations } published { Published declarations } property MyString: string read FMyString write FMyString; end;
The fields that hold the property data are usually added to the private section of the class. The private section is perfect for field declarations because it enables you to hide fields from the outside world. By hiding a field in the private section, you allow access to the field only through the property, which is usually declared in one of the other three sections and perhaps has a write method that controls how the field is accessed.
Note | Although it's not necessary, you should always begin the field's name with the letter F and the component's name with the letter T. |
The private, protected, public, and published reserved words define the visibility of class members. Private members are generally inaccessible from the outside world, although they can be accessed by code that resides in the same unit. If you want to have a really private field, one that can't be accessed in the same unit or from other units, place it in the strict private section:
type TSomeClass = class(TAnotherClass) strict private { strict private fields can only be accessed inside the class } FMyString: string; private { private fields can be used by code inside the class and in the same unit } end;
To an application developer, the protected section is the same as the private section, since protected members, like private members, cannot be accessed from outside units. The protected section and the protected members are only useful to component developers because you can access all protected class members in a descendant class, regardless of the unit in which the descendant class is declared. Like private fields, protected fields can be used by code that resides in the same unit. To have a field that can be used in a descendant class but not by code in the same unit, place it in the strict protected section.
At the beginning of your component development career, you'll mostly create public and published properties, simply because they can be used throughout the application. If you declare a public member, it will be available wherever the object is available.
Properties are added to the published section of the class when you want them to appear in the Object Inspector at design time. Published properties are similar to public properties because they are globally accessible. The difference between public and published properties is that the Delphi compiler generates run-time type information (RTTI) for published properties, which enables them to be displayed in the Object Inspector and saved to and loaded from .dfm files.
Now that we've covered the visibility of class fields, it's time to finish the TSimple component. Since you've already declared the MyString property in the published section of the TSimple component, you can now recompile the package and then drop a TSimple component on the Designer Surface (if you haven't done that already) to see what your first property looks like in the Object Inspector.
Figure 24-7: The MyString string property
Besides string properties, the Object Inspector considers character and numerical properties to be simple properties. All simple property types are displayed as directly editable strings in the Object Inspector.
The following listing shows the TSimple component with four different properties.
Listing 24-2: Simple properties
type TSimple = class(TComponent) private { Private declarations } FMyChar: Char; FMyDouble: Double; FMyInteger: Integer; FMyString: string; protected { Protected declarations } public { Public declarations } published { Published declarations } property MyChar: Char read FMyChar write FMyChar; property MyDouble: Double read FMyDouble write FMyDouble; property MyInteger: Integer read FMyInteger write FMyInteger; property MyString: string read FMyString write FMyString; end;
Figure 24-8 shows how the Object Inspector displays all simple properties.
Figure 24-8: Simple properties
Boolean and enumerated properties are, like simple property types, displayed as directly editable strings. However, the Object Inspector also allows you to select one of the possible values from a drop-down list.
The following listing shows the TSimple component with a Boolean and an enumerated property. The four simple properties displayed in Listing 24-2 were removed to save space and also to illustrate what happens in the IDE when you remove published properties.
Listing 24-3: Boolean and enumerated properties
type TDaysEnum = (deMonday, deTuesday, deWednesday, deThursday, deFriday, deSaturday, deSunday); TSimple = class(TComponent) private { Private declarations } FEnumeration: TDaysEnum; FBool: Boolean; protected { Protected declarations } public { Public declarations } published { Published declarations } property Bool: Boolean read FBool write FBool; property Enumeration: TDaysEnum read FEnumeration write FEnumeration; end;
After you remove a published property from a component and recompile the package where the component resides, you will receive the error shown in Figure 24-9 when you try to display a form that uses an older version of your component. The error occurs because the IDE tries to load a value from the .dfm file into a property that no longer exists.
Figure 24-9: This happens when you delete published properties
Since you've deleted the properties, it must mean that you have no need for them and thus the best thing to do is to click the Ignore All button to have the IDE remove the old property values from the .dfm file and display the Designer Surface.
The following figure shows how the Object Inspector displays Boolean and enumerated properties.
Figure 24-10: Boolean and enumerated properties
Set properties are displayed in the Object Inspector the same way they are in the code, as a comma-delimited list of values inside square brackets. Set values can also be expanded and treated as a list of Boolean values. By setting a specific value to True, you include it in the set.
The following listing shows the TSimple class with the previously created Boolean and enumerated properties along with the new set property, WorkDays.
Listing 24-4: A set property
type TDaysEnum = (deMonday, deTuesday, deWednesday, deThursday, deFriday, deSaturday, deSunday); TDays = set of TDaysEnum; TSimple = class(TComponent) private { Private declarations } FEnumeration: TDaysEnum; FBool: Boolean; FWorkDays: TDays; protected { Protected declarations } public { Public declarations } published { Published declarations } property Bool: Boolean read FBool write FBool; property Enumeration: TDaysEnum read FEnumeration write FEnumeration; property WorkDays: TDays read FWorkDays write FWorkDays; end;
The following figure shows how set properties are displayed in the Object Inspector and how you can manage individual set values.
Figure 24-11: A set property