Alternative to calling the Loaded method explicitly for dynamically created instances of a VCL component in Delphi 6? - delphi

I have several custom VCL components that do important tasks in their override of the TComponent Loaded() method. This creates a nuisance when creating instances dynamically since the Loaded() method is not called by the Delphi global loader during run-time, like it does for components that were placed on forms/frames at design-time. I also have to place the Loaded override in the public section of the class declaration so whatever code that creates an instance of the component can call it. Finally I have to remember to call Loaded() for dynamically created instances or subtle bugs will creep into the application, a problem that has bit me several times already.
Is there a better solution or approach to this?

If you need to call Loaded in your code you're doing it wrong. If you depend on a third party control that does, then I would fix that person's control. See below for how.
Let me make up a hypothetical example: Suppose I had 5 published properties, which once they are all loaded, can generate a complex curve or even better, generate a fractal, something that takes a long time.
At designtime I want to preview this curve, as soon as it's loaded, but I don't want the curve to be recalculated 5 times during DFM streaming, because each parameter P1 through P5 (type Double) has a SetP1 method, which invokes a protected method called Changed, and rebuilds my curve. Instead I have the SetP1 method return if csDesigning or csLoading are in the component states, and I then invoke Changed once, from Loaded. Clearly I can't rely on property setter methods alone, in all cases, to invoke all changes. So I need Loaded to tell me to do my first generation of some expensive work, that I want to be done 1 time exactly, not N times, where N is the number of DFM properties that would have been loaded that had method set procedures that invoked a method named Changed or something like that.
In your case, at runtime, you should not be relying on Loaded getting invoked at all. You should be instead, having your property set methods call Changed. If you need some way to change multiple properties at once, and then do some expensive thing only once, then implement a TMyComponent.BeginUpdate/TMyComponent.EndUpdate type of method call, and avoid extra work.
I can think of NO useful places where doing something from Loaded makes any sense, except for cases like the ones above, which should be specific to designtime and DFM based class use. I would expect a properly designed TComponent or TControl to properly initialize itself merely by being created in code, and by having its properties set.
So for my hypothetical TMyFractal component, I would do this when creating it in code without it ever having used DFM loading, or invoking Loaded:
cs := TMyFractal.Create(Self);
cs.Parent := Self; {Parent to a form}
cs.Align := alClient;
cs.BeginUpdate;
cs.P1 := 1.03; // does NOT trigger Regenerate
cs.P2 := 2.3;
cs.P3 := 2.4;
cs.P4 := 2.5;
cs.EndUpdate; // triggers expensive Regenerate method .
cs.Show;
// later someone wants to tweak only one parameter and I don't want to make them
// call regenerate:
cs.P5 := 3.0; // Each param change regenerates the whole curve when not loading or in a beginupdate block.
In my TMyFractal.Change method, I would invoke the expensive RegenerateCurve method once, each time any coefficient P1-P4 is modified at runtime, after initial setup, and once exactly when the component is streamed in from DFM, where Loaded is only used to handle the fact that I can hardly expect to do a beginupdate/endupdate in my control like I would have done in the code above.

Related

Delphi 2009 creates my components in wrong order

Three components, working together:
* CompA, a TComponent descendant, a mastermind component knowing many things and tying things together
* CompB, a TComponent descendant, mines some data from it's CompA and crunches it. Can amongst other things feed CompC with data to present
- Has a published property of type CompA
* CompC, a TComponent descendant, a TFrame descendant drawing surface that can be set at designtime to use a CompB as data provider
- Has a published property of type CompA
- Has a published property of type CompB
I think I remember having read, even though I cannot state where, that Delphi's streaming engine reads all components from the .dfm and builds a dependency graph. This graph is then used to create all components in correct order. For the listed components it should be CompA first (since it uses none of the other ones), then the CompB (it uses CompA and must be created after) and lastly the CompC since it has properties of both the other component types.
This does not happen. CompC is created before CompB. If i rearrange the order in the .dfm file using a text editor it works. The property values are not used in any constructors, only in the Loaded procedures. But truly there must be a way to make it work no matter the order of components in the dfm?
I've been banging my head against the wall for two days straight now, I need somebody to tell me which keyword I forgot or what error in design I have.
I suspect your fault is you're trying to access other objects properties on setters for sibling pointers, forgetting that at dfm loading stage --runtime-- you can't be sure pointers to other components your component depends on are yet valid because it is possible that other component is not yet created. This works this way since Delphi 1.
Because of this, you usually deffer the reading of other component's state (for example) to your overridden Loaded method.
When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.
Note: All references to sibling components are resolved by the time Loaded is called. Loaded is the first place that sibling pointers can be used after being streamed in.
Because of this, usually on a setter method for a sibling pointer property you usually perform a check of this type:
procedure TMyComponent.SetDataSource(Value: TDataSource);
begin
FDataSource := Value;
//streaming in stage
if not (csLoading in ComponentState) then
ReadDataSourceProperties;
end;
procedure TMyComponent.Loaded;
begin
ReadDataSourceProperties;
end;
Take a look at the VCL source, you'll find hundreds of examples of this.
If your components are that much dependent on creation order, you are always going to be in trouble relying on the streaming mechanism. Just one addition or removal of a(n other) component on the form/datamodule can throw your order out of whack.
To ensure proper creation order, you'd be better off creating them at run time. Just note that when you create components at run-time the Loaded method will not be called. You will either have to do it yourself or move the code to some init method that you call after you create your components.
You can right click a form/datamodule and select the "Creation order" item. It will allow you to select the creation order of "non visual" components. Visual ones should follow the tab order, but I am not really sure about that.
Update: I was wrong about the tab order, but it looks the visual controls are streamed to the .dfm in Z-order. If the controls are instantiated following the order they are in the .dfm, you can use Edit -> Bring to front/send to back (or the Control menu in the form context menu) to change the z order. As long as the controls do not overlap you should be enough free to change it.

Make sure nested child control is visible

I have a utility routine that I call when validating user input in a dialog fails. It sets focus to the offending control, beeps and displays an appropriate message to the user. This works well as long as the offending control is not hidden. Now I have to adapt this to a situation where the relevant controls are children of some kind of collapsible group boxes (possibly even nested), and I have to make sure that the "ancestor" boxes are expanded before calling SetFocus.
Now I have a few possibilities:
Build knowledge about the collapsible component into the error reporting routine. I'd like to avoid that as the routine should rather stay generic.
Pass an callback that can be called prior to (or instead of) SetFocus. This is error prone because one has to remember to pass the callback at all the relevant places.
My favourite solution would probably be an event (or overrideable method) (probably in TWinControl) that tells a container control "please make sure you and you child controls are visible" but I don't know of such a thing.
Any ideas how I can handle this situation?
Define an interface with a method called something like: EnsureVisible.
Implement it for all your components (you may need to derive your own versions of some of these components). This allows different controls to have quite different behaviour.
When a control needs to make sure it is visible it walks its parents and calls EnsureVisible if the interface is implemented.
If you don't like interfaces then do it with a custom Windows message, but you get the basic idea.
In my opinion the best solution would be a separate routine that builds knowledge about all container controls, allowing the dialog validation routine to stay generic and at the same time being focused enough to be easily tested and maintained. Something along the lines of:
procedure ForceControlVisible(C: TControl);
begin
// Recursive code
if Assigned(C.Parent) then ForceControlVisible(C.Parent);
// Code specific to each container control class
if C is TTabSheet then
begin
// Code that makes sure "C" is the active page in the PageControl
// goes here. We already know the PageControl itself is visible because
// of the recursive call.
end
else if C is TYourCollapsibleBox then
begin
// Code that handles your specific collapsible boxes goes here
end
end;
OOP-style methods that rely on virtual methods or implementing interfaces would be way more elegant, but require access to the source code of all the controls you want to use: even if you do have access to all required sources, it's preferable not to introduce any changes because it makes upgrading those controls difficult (you'd have to re-introduce your changes after getting the new files from the supplier).
Each component knows its Parent. You can walk up the list to make each parent visible.

What is called after Loaded() in Delphi

I have some code that does some setup of internal objects in the Loaded() function. However, some external objects are not completely created yet, but are AFTER the Loaded() function is complete. What function does Delphi call after it calls Loaded()?
Better yet what is the creation sequence of a component?
Basically I have a TCP Server and Client. Most people will place those two components into two separate applications, some will place them in the same application for local access.
My Client tries to fetch data from the server in OnLoaded(), but the server may not be up yet! I want to know if another function is called after all the OnLoaded()'s are called.
Loaded is called immediately after the dfm is streamed in, and shouldn't be used to access the server. Your best bet is probably to post a custom message to yourself in the constructor, and have a message handler procedure that responds to that message. Posting the message puts it into the end of the message queue, and therefore it won't get processed until all the other messages ahead of it has been handled. This should delay things long enough for your components to be fully constructed for use.
I've used breakpoints in some components and firmly established that AFTERCONSTRUCTION is called BEFORE LOADED not AFTER.
I've also done the same thing on a FORM and firmly established that AFTERCONSTRUCTION is called AFTER LOADED not BEFORE.
Bear in mind that AfterConstruction is a method in TObject, but Loaded is not. It follows that Loaded is generated by code that may not necessarily put it in a specific order relative to AfterConstruction, since Loaded is not actually part of the construction sequence of a TObject and AfterConstruction is.
Indeed, if you study the RTL source, you will see that Loaded is not even invoked by any self.method of a TComponent, but is in fact invoked by a stream reader that is reading the DFM, and that will most probably be happening under the control of an "owner" component. I strongly suggest therefore that its relationship relative to the execution of AfterConstruction is not really guaranteed. The fact that it appears in a particular order for a form is because the form is most likely the component to initiate stream reading. In other words, it smacks of a convenient accident that Loaded is before AfterConstruction in a form.
Further research shows that NON-FORM components that include the following code may never call the event handler.
procedure Txxx.AfterConstruction; override;
begin
inherited AfterConstruction;
if Assigned(FOnCreate) then FOnCreate(Self);
end;
The reason is that AfterConstruction, if invoked before properties are loaded, will find FOnCreate has not been assigned yet!
In such cases, you really HAVE to use the following:
procedure Loaded; override;
begin
inherited Loaded;
if assigned(OnLoaded) then OnLoaded(self);
end;
Like I said, this will produce different outcomes for a component owned by a form than it would for the form itself! The TForm component is usually the invoker of the DFM stream reader and it is the stream reader that calls Loaded for each component it reads from the form. This process starts (fortunately) BEFORE the form's AfterConstruction, but each component that is loaded by that reader gets its AfterConstruction method called BEFORE its loaded method.
QED.
The great irony is that the Delphi 6 help file says "The AfterConstruction method implemented in TObject does nothing. Override this method when creating a class that takes some action after the object is created. For example, TCustomForm overrides AfterConstruction to generate an OnCreate event."
What it omits to say is that if you try this on anything other than a TCustomForm (which does it already), it doesn't work! Because only a form (which has it already) will load its OnCreate property before calling AfterConstruction. Any other component won't, because the DFM reader invoked by the form calls AfterConstruction before Loaded! A clear case of Borland et. al. not understanding their own code, or at best, writing a help file entry that implies something is possible when in fact it is not.
Note, if your component is not on a form and is created at runtime (even if this is as an "owned" component), its "Loaded" method will NOT be called, because there was no stream reader involved.
Another point of interest is something that "Dr" Bob Swart wrote some time ago about AfterConstruction, namely that it represents the point where virtual methods can be invoked. Evidently this is only partly true: if a form's Loaded method is invoked BEFORE AfterConstruction, then you would not be able to invoke any virtual methods from Loaded if that were true. This is not the case (obviously) because Loaded is itself a virtual method! Evidently, Loaded for a form is called between the constructor and AfterConstruction by the stream reader. It begs the question: by what method is the stream reader actually invoked? My guess is either that it runs under control of the application (not the form) and that it deliberately invokes AfterConstruction differently for a form than for other components, OR that it is the last thing the form's constructor does after having created the VMT and hence the last thing that occurs before AfterConstruction is called in the form. Accordingly all the AfterConstruction-Loaded couplets of components owned by the form are called before the form's AfterConstruction is called. Tracing the calls also shows that mostly AfterConstruction is called for ALL of those components before ALL of their loaded methods are called. I didn't however test the case where there are hierarchical "parents" (such as panels with components on them), so there may be variations on this.
Normally you would override TObject.AfterConstruction for that purpose.
The order of execution is:
each Component.AfterConstruction in creation order
(Form or DataModule).Loaded
each Component.Loaded in creation order
(Form or DataModule).AfterConstruction
Trace:
Debug Output: button AfterConstruction Process Project2.exe (4876)
Debug Output: Form Loaded Process Project2.exe (4876)
Debug Output: button Loaded Process Project2.exe (4876)
Debug Output: Form AfterConstruction Process Project2.exe (4876)
I'm not sure what you mean with
the server may not be up yet
Anyway, if the client and the server are both on the same application form or datamodule, I see alternatives:
You may "force" the system to create the server before the client and up the server in the server's OnLoad and it will be up at the client OnLoad, because documentation says:
When the streaming system loads a form or data module from its form file, it first constructs the form component by calling its constructor, then reads its property values from the form file. After reading all the property values for all the components, the streaming system calls the Loaded methods of each component in the order the components were created. This gives the components a chance to initialize any data that depends on the values of other components or other parts of itself.
Inform the "client" whenever the server is UP to let it initialize (pull data from the server). You can use a direct method call, post a message or whatever you feel comfortable with.
Let the client stand up the server inside it's own OnLoad method.
Why not use the onCreate event of the main Form ?

Creating a compound control (parent of other controls) at runtime

I has a piece of code where I override TStringGrid's inplace editor and the hint window. For this, I created my own string grid based on TStringGrid and use a TEdit for inplace editor and a TPanel for tool tips. In TMyStringGrid.Create constructor I initialize them like this:
Constructor TMyStringGrid.Create();
Begin
inherited Create(AOwner);
MyEditor:= TEdit.Create(Self);
MyEditor.Parent := Self;
End;
In this case the owner (the main form) is freeing the controls. I used this for years and it worked.
The thing is that other people argue that the programmer should use NIL instead the Self when instantiation the child controls and later to manually free them in the Destroy destructor. It seems that the second alternative has gigantic advantage over the first one, especially when you dynamically create lots of child controls (not my case). Other problem with my code, they say, is that the child controls may be freed after an Application.ProcessMessages call while the application may still want to use them.
So, I should let my code unchanged or should I manually create and free the child controls?
There is a any Borland example of compound controls?
Delphi 7, Win XP
Reference: http://delphi.about.com/od/kbcurt/ss/dynamiccreateno.htm
Yes you can use your code without changing it.
There is a any Borland example of compound controls?
Best example is to check the implementation of TLabeledEdit.
It was creating the label in constructor
if Assigned(FEditLabel) then exit;
FEditLabel := TBoundLabel.Create(Self);
FEditLabel.FreeNotification(Self);
FEditLabel.FocusControl := Self;
There's no good reason to pass nil instead of Self in this situation. That AOwner parameter is there specifically for that reason. Take advantage of it.
There's a reason to pass nil when creating a control and manually destroy it, but for a completely different situation: if you're creating a control (typically a form) inside a function. This is a pretty common pattern, for example:
MyDialog := TMyDialog.Create(nil);
try
result := MyDialog.ShowModal;
finally
MyDialog.Free;
end;
There, you want to free it immediately instead of waiting around until the current form gets destroyed, which could be much later. But when it comes to sub-components, you usually want them to be destroyed at the same time as the parent component, not later, so pass Self to AOwner and let the VCL take care of it for you.
Considering that constructor, the grid instance is owned by Aowner (which is tipically a TForm or a TFrame). The inplace editor is owned and parented by the grid instance. I don't see how ProcessMessages would cause destruction of the child objects, since they will be destroyed in the destroying loop of TMyStringGrid. That's nothing I can see of wrong on that implementation - and I use that same design for the components I create. Ownership is there on VCL to easy our lifes when managing objects' lifetime. And is not the case where nil is recomended as owner, which is shown in Mason' answer.
In the pattern shown by Mason , the reason for the NIL is that, without a owner, the object destruction will not enter in a Notification loop. If you create a lot of components which destruction you handle manually, you want to make sure the owner is NIL, otherwise a lot of code get executed (without need) in each component construction/destruction.
Many moons ago, there was an excelent white paper on the web archive of (now defunct) eagle-software.com

What's the difference between CreateWnd and CreateWindowHandle?

Delphi components have CreateWnd and CreateWindowHandle (and DestroyWnd and DestroyWindowHandle). They're both intended to be overridden by descendants, right? And not intended to be called except by the underlying VCL implementation?
What's the difference between them; when should either of them be overridden?
So far most of the answers here are pretty much on the mark and you would do well to heed their advice. However, there is a little more to this story. To your specific question about when you would override one or the other, I'll try and nutshell things a little bit.
CreateParams();
In general, most of the time all you really need to do is to override CreateParams(). If all you want to do is to subclass (remember Windows style "subclassing?" See Petzold's seminal work on Windows programming) an existing control class and wrap it up in a VCL control, you do this from CreateParams. You can also control what style bits are set and other various parameters. We've made the process of creating a "subclass" very easy. Just call CreateSubClass() from your CreateParams() method. See the core VCL controls for an example such as TCheckBox or TButton.
CreateWnd();
You would override this one if you need to do a little bit more with the window handle once it is created. For instance, if you have a control that is some kind of list, tree, or otherwise requires post-creation configuration, you'd do that here. Call the inherited CreateWnd, and when it returns (you know you have a valid handle if you return from CreateWnd because it will raise an exception if something went awry), just apply your extra magic. A common scenario is to take the data that is cached in an instance TStrings list and actually move it into the underlying window control. The TListBox is a classic example of this.
CreateWindowHandle();
I had to go refresh my memory on this one, but it seems this is one is rarely, if ever, overridden. In the few cases inside VCL itself, it appears that it is used to work around specific Windows version and locale oddities with some controls, such as the TEdit and TMemo. The other more clear-cut case is in TCustomForm itself. In this case it is there to support the old MDI (mutli-document interface) model. In this case MDI children cannot be created using the normal CreateWindowEx() API, you have to send a message to the MDI parent frame to actually create the handle. So the only reason to overide this method is if the actual process of creating the handle is done via a means completely different than the old tried-and-true CreateWindowEx().
I did notice that your question was merely asking about the creation process, but there are corresponding methods that are overridden in some cases for both handle destruction and the "voodoo" that sometimes surrounds handle recreation. But these are other topics that should be covered separately :-).
CreateWnd first calls CreateParams, then calls CreateWindowHandle using the created Params. Generally, you'll override CreateWnd and CreateParams rather than CreateWindowHandle.
I hope this helps!
Who does what:
CreateWnd is the general contractor that creates the fully formed window for a WinControl.
First, it has to set the required attributes for the WindowClass by calling CreateParams and making sure it is correctly registered.
Then it gets the window actually created, by calling CreateWindowHandle which returns the resulting Handle from the OS.
After that, we have a valid window able to process messages, and CreateWnd does the final grooming, adjusting different visual aspects like size, font, etc.
There is also later step done by CreateHandle, after CreateWnd is finished, to help the VCL in managing its windows (identification, parentage,...).
I'm sure that the final answer can only come from the people involved in the creation of the VCL (Allen?), but IMHO the virtual method with the least responsibility / which is lowest in the chain of calls should be overridden. That's why I have always overridden CreateParams() and CreateWindowHandle(). This looks like a good fit since they are both called by CreateWnd(), and both do only one special thing.
In the end it's probably a matter of preference.

Resources