Delphi 2009 - Set default property values in custom delphi components
-
20-09-2019 - |
Question
This should be very simple but I can't find the exact answer I want. I have a custom delphi control based on TSpeedButton. I want the Caption Property of the SpeedButton to always be 'Comments' but I don't want to set it at run-time I want to set it in the component itself so that when I place it on my form it's already populated with this text. I also want to set the height and width of the button but I imagine the method for doing this will be the same as for setting the caption.
For the sake of completeness, here is the component code:
unit CustomSpeedButton;
interface
uses
SysUtils, Classes, Controls, Buttons;
type
TCustomSpeedButton = class(TSpeedButton)
private
FCommentText: string;
FCommentTitle: string;
procedure SetCommentText(const Value: string);
procedure SetCommentTitle(const Value: string);
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
property CommentTitle: string read FCommentTitle write SetCommentTitle;
property CommentText: string read FCommentText write SetCommentText;
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Standard', [TCustomSpeedButton]);
end;
{ TCustomSpeedButton }
procedure TCustomSpeedButton.SetCommentText(const Value: string);
begin
FCommentText := Value;
end;
procedure TCustomSpeedButton.SetCommentTitle(const Value: string);
begin
FCommentTitle := Value;
end;
end.
Solution
Since you wanted the Caption property to be done properly, Mason's answer is not going to work because he missed the 'csSetCaption' thing, and his suggestion about 'default' will not work either because both the Caption and your properties are string types.
Below are the units as you want them.
The behaviour is as follows:
- intially the value of the Caption property will be 'Comments'
- users can override that at design time by setting a new value
(If you do not want 2., then you need to assign the Caption property in an overrided Loaded method like Ken mentioned; however, it was not clear from your question if you wanted that. If you do, then please rephrase your question.)
This is how the code works.
For string properties, you cannot hint the streaming system of any default. But you can set an initial value for design time in the constructor: Caption := DefaultCustomSpeedButtonCaption;
For the Caption property, you must also disable the default assignment of the Caption property (otherwise your component would be automatically get a caption like 'CustomSpeedButton1'). This line does that for you: ControlStyle := ControlStyle - [csSetCaption];
Finally it is good practice to split your component registration into a separate unit. That allows you to have a design-time package that registers your components in the IDE and a run-time package (or no package at all) for using your components in your applications.
If you have a component icon, then you load that in the registration unit as well (since it is only needed at design time).
Ray Konopka has written an excellent book on component writing which is still very valid: Developing Custom Delphi 3 Components Like many good Delphi books, it is out of print, but you can order a PDF copy on his site.
I'm not sure what your CommentTitle and CommentText properties are for, so I have kept them in the source below.
Listing 1: actual component
unit CustomSpeedButtonUnit;
interface
uses
SysUtils, Classes, Controls, Buttons;
const
DefaultCustomSpeedButtonCaption = 'Comments';
type
TCustomCustomSpeedButton = class(TSpeedButton)
strict private
FCommentText: string;
FCommentTitle: string;
strict protected
procedure SetCommentText(const Value: string); virtual;
procedure SetCommentTitle(const Value: string); virtual;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property CommentTitle: string read FCommentTitle write SetCommentTitle;
property CommentText: string read FCommentText write SetCommentText;
end;
TCustomSpeedButton = class(TCustomCustomSpeedButton)
published
// note you cannot use 'default' for string types; 'default' is only valid for ordinal ordinal, pointer or small set type
// [DCC Error] CustomSpeedButtonUnit.pas(29): E2146 Default values must be of ordinal, pointer or small set type
// property Caption default DefaultCustomSpeedButtonCaption;
property CommentTitle;
property CommentText;
end;
implementation
constructor TCustomCustomSpeedButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
Caption := DefaultCustomSpeedButtonCaption;
ControlStyle := ControlStyle - [csSetCaption];
end;
destructor TCustomCustomSpeedButton.Destroy;
begin
inherited Destroy;
end;
procedure TCustomCustomSpeedButton.SetCommentText(const Value: string);
begin
FCommentText := Value;
end;
procedure TCustomCustomSpeedButton.SetCommentTitle(const Value: string);
begin
FCommentTitle := Value;
end;
end.
Listing 2: component registration
unit CustomSpeedButtonRegistrationUnit;
interface
procedure Register;
implementation
uses
CustomSpeedButtonUnit;
procedure Register;
begin
RegisterComponents('Standard', [TCustomSpeedButton]);
end;
end.
OTHER TIPS
You need to set the original values in the component's constructor.
EDIT: You'll also want to put add ControlStyle := ControlStyle - [csSetCaption];
to the constructor.
@Etherman: In case you want to have a string property with default value AND you want to save it to DFM - even if it is BLANK - you have to do it yourself. Fortunately, Delphi gives you methods to do that. Take a look at this code:
type
TMyComp = class(TControl)
private
FMyStringProperty: string;
procedure WriteMyStringProperty(Writer: TWriter);
procedure DefineProperties(Filer: TFiler); override;
public
constructor Create(AOwner: TComponent); override;
published
property MyStringProperty: string read FMyStringProperty write FMyStringProperty stored False;
end;
implementation
constructor TMyComp.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FMyStringProperty := 'my default value';
end;
procedure TMyComp.WriteMyStringProperty(Writer: TWriter);
begin
Writer.WriteString(FMyStringProperty);
end;
procedure TMyComp.DefineProperties(Filer: TFiler);
begin
inherited DefineProperties(Filer);
Filer.DefineProperty('MyStringProperty', nil, WriteMyStringProperty, True);
end;