Discussion:
Form Initialization Woes
(too old to reply)
Jason Cipriani
2008-07-11 07:24:31 UTC
Permalink
Where is the best place to initialize GUI components (and other application
stuff) if you have to do it *after* all VCL components (including all forms)
have been loaded? Is there an event, or some good place to do this?

For example (this is contrived, but it illustrates the point): Say I have
two forms, Form1 and Form2, and each form has a TLabel on it. Also say each
form has a TLabel * member variable that should be set to the TLabel on the
other form. How can I do this (while doing it immediately before showing one
of the forms works for this particular example, that's *not* the solution
I'm looking for).

I find that I am frequently using one-shot TTimers to initialize this kind
of stuff (initially disabled, enabling in main form create, with a short
interval). It really seems pretty sloppy. There has to be a better way.

Thanks,
Jason
dhoke
2008-07-11 12:59:49 UTC
Permalink
Post by Jason Cipriani
Where is the best place to initialize GUI components (and other
application stuff) if you have to do it *after* all VCL components
(including all forms) have been loaded? Is there an event, or some good
place to do this?
I've created an "AuxiliaryInitialization()" function that I call just before
the projects Application->Run(), which is just after all auto-created forms
have been Application->CreateForm()d (the system created calls.)

Don't know if that might work for you or not.
Post by Jason Cipriani
Thanks,
Jason
Vladimir Stefanovic
2008-07-11 16:45:51 UTC
Permalink
Post by Jason Cipriani
I find that I am frequently using one-shot TTimers
to initialize this kind of stuff (initially disabled,
enabling in main form create, with a short interval).
It really seems pretty sloppy.
There has to be a better way.
From my experience, the OnPaint() is last
executed. I've used this approach a lot in
the past, and never had any problems.

void __fastcall TForm1::Form1Paint()
{
static bool HasPassedOnce = false;
if ( !HasPassedOnce )
{
HasPassedOnce = true;
ExecuteYourFinalCode(); // <-- finall code here
}
}
--
Best Regards,
Vladimir Stefanovic
Clayton Arends
2008-07-11 17:07:50 UTC
Permalink
Post by Jason Cipriani
Where is the best place to initialize GUI components (and other
application stuff) if you have to do it *after* all VCL components
(including all forms) have been loaded? Is there an event, or some
good place to do this?
I don't know of a best approach given that I haven't run into this
particular design requirement yet. One idea I can think of is to use a
common class that handles the distribution of component pointers. This
could be done through the use of a singleton, added to a common datamodule,
etc.

Using your example let's say you want to share the labels from Form1 and
Form2 with each other. Neither form should have to care whether the other
form has yet been created. I'm going to use a common datamodule which
should be the first thing created by your application. You can just as
easily use a singleton class instead. This is a generic approach which can
be used by any number of other forms and components.

class TMyDataModule : public TDataModule
{
...
private:
void CallHooks(String Name);

public:
typedef void (__closure *THookCallback)
(String Name, TComponent* AComponent);

void AddHook(String Name, THookCallback Callback);
void AddHookedComponent(String Name, TComponent* Component);
};

'Name' is a special unique identifier that you have configured in your
system. It could simply be "FormName.ComponentName" and would be
sufficient. The datamodule would have some map, list, vector, etc that
stores a list of callbacks for a particular name and the associated
component. AddHook is called by the forms that want to be notified when the
component is created. AddHookedComponent is called by the form that owns
the created component. Both of these methods invoke CallHooks to iterate
the list of callbacks.

So, in practice here is how things might go down:

TForm1::TForm1()
MyDataModule1->AddHook("Form2.Label1", &HookForm2Label1);
MyDataModule1->AddHookedComponent("Form1.Label1", Label1);

TForm2::TForm2()
MyDataModule1->AddHook("Form1.Label1", &HookForm1Label1);
TForm2::HookForm1Label1() is called by TMyDataModule
MyDataModule1->AddHookedComponent("Form2.Label1", Label1);
TForm1::HookForm2Label1() is called by TMyDataModule

At this point each forms' labels have been made known to the other.

HTH,
Clayton
Remy Lebeau (TeamB)
2008-07-11 17:55:47 UTC
Permalink
Post by Jason Cipriani
Where is the best place to initialize GUI components (and other
application stuff) if you have to do it *after* all VCL components
(including all forms) have been loaded? Is there an event, or some
good place to do this?
Have the MainForm start a TTimer, or post a custom message to itself. I
prefer the latter myself. Either way, the corresponding message will not be
processed until after the message loop being running after all auto-created
forms have been initialized.


Gambit

Loading...