Question

I am developing a component but I can't make it consider a property set at design-time.

The following is an excerpt of the component:

TRVEditFrame = class(TFrame)
...
    private
     { Private declarations }
        FRVEditor:TCustomRichView;
    public
     { Public declarations }
        constructor Create(AOwner: TComponent); override;
    protected
        function GetRVEditor:TCustomRichView;
        procedure SetRVEditor(Editor:TCustomRichView);
    published
        property RVEditor:TCustomRichView read GetRVEditor write SetRVEditor;
    end;
...

constructor TRVEditFrame.Create(AOwner: TComponent);
begin
    inherited Create(AOwner);
    SetRVEditor(FRVEditor);
...
end;


function TRVEditFrame.GetRVEditor:TCustomRichView;
begin
    Result:=FRVEditor;
end;


procedure TRVEditFrame.SetRVEditor(Editor:TCustomRichView);
begin
    if Assigned(Editor) then begin
        FRVEditor:=Editor;
    end;
end;

I can register the component, place it in ther form and set FRVEditor on design-time.

Problem is when I run the application the code inside SetRVEditor() is not executed because Editor=nil.

If I was able to set FRVEditor on design-time, how come that it is=nil on run time ? How can I fix this ?


I add here my further comments because the explanation is too long

@Kenneth, thank you for your reply

  • TCustomRichView is part of a third part component set that manages hypertext documents and has 4 more specialized descendents and you are right, TCustomRichView shouldn't be used in a real application.
  • TRVEditFrame is the component I am developing.

The idea behind my component is to create one single frame (hence the choice of the component TFrame) with menus, shortcuts, popup menus etc to manage each of the 4 TCustomRichView descendents.

This is exactly the reason why I use TCustomRichView: I can "slot" any of the 4 descendents into my component-frame. This is the same principle of TDatasource that can be connected with TTAble and TQuery (they have the same ancestor).

I suppose the reason why the VCL doesn't link RVEditor to the TCustomRichView descendent I set on design-time is because TFrame has no OnCreate event, like TForm for instance.

So far I managed to solve the issue by calling TRVEditFrame.SetRVEditor manually in the TForm.OnCreate that hosts TRVEditFrame but I was wondering if there are better methods to do so and that is why I have asked advice here.

I know you can create a OnCreate event for TFrames as well, maybe I can place TRVEditFrame.SetRVEditor in there but, again, I was wondering if there was a better method.

Regarding the last part of your comment, I am aware of the register procedure but take into account the component is under development. When I develope components I never install them in the IDE because I prefer to keep the test stuff outside the "official" one. I use this method and as soon as the component is ready then I register it with the procedure you mention. If I want to implement other features to the same component I can work on the test ones and keep on using the "official" one I have in the IDE at the same time.

Was it helpful?

Solution

My suggestion is to change the design in order to get the frame component referencing the custom editor by using the Notification method, instead of manually setting a property. So, change your frame class to

TRVEditFrame = class(TFrame)
...
private
 { Private declarations }
    FRVEditor: TCustomRichView;
protected
  procedure Notification(aComponent: TComponent; aOperation: TOperation); override;
public
 { Public declarations }
    constructor Create(AOwner: TComponent); override;
public
    property RVEditor:TCustomRichView read FRVEditor;
end;

The implementation of the Notification method does the magic of connecting/disconnecting the frame to the custom editor

procedure TRVEditFrame.Notification(aComponent: TComponent;
                                    aOperation: TOperation);
begin
  inherited;
  if aComponent is TCustomRichView then
    if aOperation=opRemove then begin
      if aComponent=FRVEditor then
        FRVEditor := nil;
    end else
      FRVEditor := TCustomRichView(aComponent);
end;

I don´t know if you need any special handling when an editor is set/reset to the frame, so this code does nothing in special, just assigns the component or nil to the FRVEditor data member at the proper moment.

OTHER TIPS

You should create child components.

constructor TRVEditFrame.Create(AOwner: TComponent);
begin
    inherited; // Create(AOwner);
    FRVEditor := TRichView.Create(self);
end;

DFM streaming engine may load properties of already created class, but it cannot create the class for you for two reasons:

1) DFM can not know of any special tuning done on created component, like what should be constructor parameters (if any), what constructor to use (of many), which niotifications and event handlers to attach and so on.

2) DFM can not know which type the property should be. For example i published TStrings oroperty - object of which class should be created to feel in ? TStrings? TStringList? TRichEditStringList? THashedStringList ? they all were inherited from TStrings and thus any of them is fine choice for DFM - but not for the ocmponent you write.

Thus DFM streaming subsystem is responsible for saving and loading properties of objects, but creating those object is purely your responsibility.


I believe you also may cut the corners by learning how IDE Designer creates your forms and making RVEdit a variable rather than property:

TRVEditFrame = class(TFrame)
...
    public
     { Public declarations }
        constructor Create(AOwner: TComponent); override;
    published
        var RVEditor:TCustomRichView; // just like users' forms are created by IDE
    end;

Then hopefully TFrame constructor would create the content for this variable for you. But this design is fragile because any outer code would be able by any stupid mistake to make something like MyEditFrame.RVEditor := ... and cause a memory leak and unexpected failures of all the attached connections between the editor and the frame.

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