Question

I'm writing a component which consists of many properties which are to appear in the Delphi IDE Object Inspector (published properties)...

type
  TMyComponent = class(TComponent)
  private
    FMyProperty: String;
  published
    property MyProperty: String read FMyProperty write SetMyProperty default 'Something';
  end;

However, it's not allowing me to apply a default value to a string property...

[DCC Error] MyUnit.pas(278): E2146 Default values must be of ordinal, pointer or small set type

All other property defaults work fine (Integer, Enum, etc.).

My goal is to A) not save string properties to the DFM if they're the default value, and B) show the value in the Object Inspector as Bold if it's not the default, and regular if it is. There are over 130 properties which show for this component, and about 50 of them are string properties, some with rather large default values.

Why am I not allowed to declare a string property with a default value? Is this a shortcoming with Delphi, or is there a technical reason why strings can't be defaulted?

EDIT

If you really want to know what I'm doing, I'm encapsulating Inno Setup and wrapping the functionality into a component with an extensive property/collection editor. This topic pertains to just the Setup section alone, which consists of actually over 100 properties. Only about 20 of these properties are expected to actually be used for simple implementation, and therefore I don't want all the rest of those string properties to bloat the size of the DFM (if they're set to their defaults). Based on how the component is set up, it will produce an Inno Setup script file.

Was it helpful?

Solution

Only numeric properties can have a default value specified in the property declaration. However, you can use the stored specifier instead, eg:

type
  TMyComponent = class(TComponent)
  private
    FMyProperty: String;
    function MyPropertyIsStored: Boolean;
    procedure SetMyProperty(const Value: String);
  public
    constructor Create(AOwner: TComponent); override;
  published
    property MyProperty: String read FMyProperty write SetMyProperty stored MyPropertyIsStored;
end;

constructor TMyComponent.Create(AOwner: TComponent);
begin
  Inherited;
  FMyProperty := 'my default value';
end;

function TMyComponent.MyPropertyIsStored: Boolean;
begin
  Result := FMyProperty <> 'my default value';
end;

procedure TMyComponent.SetMyProperty(const Value: String);
begin
  if FMyProperty <> Value then
  begin
    FMyProperty := Value;
    // update component as needed...
  end;
end;

OTHER TIPS

It's not clear what you're trying to do. Assigning default to a property has two uses:

  • To decide whether the property value is streamed to the DFM or not (used for ordinal or Boolean properties, usually, such as Visible - since the default would be True, there's no reason to write it to the DFM unless it's False. (See note below)

  • For array properties, to indicate that the array is the default property of the class (such as Delphi's TList.Items, where having Items the default allows you to use List[x] instead of List.Items[x] in your code.

If your intent is to provide a default value to the string so it shows in the Object Inspector, simply set the value in the component constructor. If the user has assigned a different value, the value set in the constructor will be overwritten when the DFM content is streamed in.

As far as why string default values are not allowed, this is clearly stated in the documentation (see "Storage Specifiers" (emphasis mine):

The default and nodefault directives are supported only for ordinal types and for set types, provided the upper and lower bounds of the set's base type have ordinal values between 0 and 31; if such a property is declared without default or nodefault, it is treated as if nodefault were specified. For reals, pointers, and strings, there is an implicit default value of 0, nil, and '' (the empty string), respectively.

Note: The default is used in conjunction with the stored specifier that Remy's answer describes. From the same docs linked and quoted above (same section):

When saving a component's state, the storage specifiers of the component's published properties are checked. If a property's current value is different from its default value (or if there is no default value) and the stored specifier is True, then the property's value is saved. Otherwise, the property's value is not saved.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top