Re: Getting component's name from notification parameter?

From: Raptor (bogus_at_none.com)
Date: 01/31/05


Date: Sun, 30 Jan 2005 15:00:30 -0800


Maarten Wiltink <maarten@kittensandcats.net> wrote in message
news:41fd3812$0$28977$e4fe514c@news.xs4all.nl...

> > I made no headway on getting the nonwindowed component to post a
> > message to itself,
>
> Since non-windowed controls do not have their own message loops, that
> was to be expected. I suppose they borrow the message loop of their
> Parent or perhaps the Form they're on somehow, but I don't know. So I
> stick to what I do know.
>
>
> > but when I quit butting my head against the wall
> > the following test worked with relative ease:
> [...]
> > procedure TWCMessage.WCMessage(var Msg: TMessage);
> > begin
> > if assigned(aWCMessage) then aWCMessage.Free;
>
> Does Freeing it also clear the reference? Watch your step.

Not sure what you're suggesting-- free and nil?

> > dbs(GetComponentCount); <--displays on status bar
> > showmessage('WCMessage received... ');
> > end;
> >
> >
> > constructor TWCMessage.Create(aOwner: TComponent);
> > begin
> > inherited Create(aOwner);
> > Self.Parent := FormMain;
>
> This introduces lexical dependencies that will bite you when you try
> to generalise this component.

See below.

> Is it even necessary? This is not a
> _visual_ component, you're just using a windowed control to get a
> message loop.
> (You may have tried it without a parent and found it didn't work then.
> If so, that would be useful to know.)

Yes. It demanded a parent upon startup.

> > end;
> >
> >
> > constructor TTranslate.Create(aOwner: TComponent);
> > begin
> > inherited Create(aOwner);
> > aWCMessage := TWCMessage.Create(aOwner);
> > PostMessage(aWCMessage.Handle, TM_WCMESSAGE, 0, 0);
> > ...
> > end;
>
> It looks like aWCMessage is a field in the TTranslate instance. That
> makes me think you should clear the field once you free the object
> it references.

I made it a freestanding type, but have wondered if there was any advantage
to incorporating it as a field. See next comment.

> You can make the windowed control refer to the translation component
> instead of the other way; that would minimise the impact of the
> whole scheme on the permanent part. By placing the reference in the
> inner component, it automatically goes away once the component has
> served its purpose.

The translate component will persist, as languages can be changed by user
while the app runs. This windowed thing, on the other hand, is only a
gimmick to send a message, and can be discarded when the message is
received. I can't see any need to let the window hang around for the
duration. At least I think that's what you're getting at.

> > =============
> >
>
> > I'd still like to know if there's a way to do this with a nonwindowed
> > control. Various posts speak about using Dispatch, but... ahem... no
> > code examples.
> >
> > I don't mind spawning a temporary TWinControl for this purpose, then
> > freeing it, if that's an acceptable/best/only way, but I did have
> > one problem: I couldn't find a way to assign it a parent except by
> > specific reference... thus couldn't come up with a way to genericize
> > the code which compiled or worked.
>
> Spoke before my turn, I see.
>
> Well, as I said you may not need to - although I have some faith that
> if you ask about it, you already know that you do. It's possible to
> check that the Owner is not just a TComponent but a TWinControl, and
> use that if it is.
>
> The Owner is passed from the TTranslator instance to the TWCMessage
> and _usually_ it will be the form, which then works fine. Of course,
> someone someday will instantiate your translator component at runtime
> and not pass it an Owner at all.

> That may not be a problem because of the unique and very specific
> circumstances that created the need for message processing in the
> first place - if the application is already up and running, you don't
> need it anymore.

Correct. It's only a startup gimmick. At startup the app needs to do things:
Save a copy of the native language file as a template for translators
(especially if one does not exist), and load the last language file the user
was running.

But I'm still not getting how to generically locate the parent it demands at
startup. This compiled and looked syntactically promising:

constructor TWCMessage.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);
  Self.Parent := Application.MainForm;

but still demands a parent window on startup. What's with that, I wonder.
Maybe the MainForm is assigned later in the startup process.

> Of course, when you deem yourself secure in that, the
> day will come that someone integrates it into their custom form class
> and manages to instantiate TTranslator without an Owner while forms
> are still being autocreated.
>
> So scenarios remain possible where you _need_ a Parent for the inner
> component, and you just don't have one. You can give the outer
> component a Parent property and pass it to the inner component, or
> you can have the inner component query the outer component for it.

I'll look at that "give the outer component a Parent property" notion. But
that I assume that my TTranslate would become the parent for my TWCMessage
(which I've renamed to TAppLoadedMsg). That sounds vaguely promising.

> The outer component can give its own best guess or pass on the
> request by firing an event. Let me know if you decide to use any of
> those techniques and I'll jot down some example code. But not right
> now; dinner's waiting.

Never stand between an animal and its primary food source. Heh.

> > Would that problem disappear somehow if I turned this into a
> > Registered drop-on component?
>
> Only if you drop it on a form, because the form will become the Owner
> and it's also useable as the Parent. But it remains possible to
> create it outside Delphi's designers system, and it should not stop
> working then.

True enough. Just like I'm invoking a windowed class. I've no plans to
actually distribute this, as it's really more an effort to a) learn
component writing and b) organize/advance the application framework, but
it's good to behave as though I were trying to make it ready for prime time.
Make it standalone and the like... you get it.

> > PS to Maarten: Happy to note that the component count when this message
> > received is 73, the same count as on app closure, which says that even
> > the dynamically-created menu items (called from TFormMain.FormActivate)
> > are being included before the message is returned.
> >
> > You think that's a dependable circumstance?
>
> No. TForm.OnActivate occurs (for the first time) during component
> streaming while autocreating forms, but many dynamic schemes are most
> active while the application is fully up and running.

Makes sense.

> TForm.OnActivate is almost always the wrong place to do things, BTW.
> Look into TComponent.Loaded instead.

I will. Thanks.

Raptor


Quantcast