I went through each of my dfm's by hand and added the 'OldCreateOrder =
False' entries, but, in BCB5, *any time* I save a form where the dfm has
been modified (including simply moving the form to a different location on
screen within the IDE), the saved dfm no longer contains my 'OldCreateOrder
= False' entries. After about the third (not to mention the twenty third)
time this happens, and I have to go manually fix the dfm yet again, it wears
a bit thin... I have tried right clicking the properties tab and viewing
legacy properties to change OldCreateOrder to false directly from the object
inspector, but the setting doesn't stick and I still have to go correct the
form by hand (i.e. convert the form to text, add the 'OldCreateOrder =
False' entry, then convert the form back to a dfm.)
To answer a specific question, when, exactly, is my vtable initialized?
Also, what, if anything, comes between my constructor call, FormCreate, and
FormShow? If my vtable is not yet initialized until after the ctor returns,
and FormCreate can be called at any time (usually before the ctor finishes
its initialization), then how can I get a one-time initialization of my form
based upon it's most derived state (without introducing some 'initialized'
boolean...) Is there any place that I can reliably have access to a virtual
function before FormShow is called?
Hope this all makes sense...
Thanks,
Ken
Matt
It is best to think of OnCreate/OnDestroy as 'legacy/Delphi only' events
because they can cause subtle bugs. When handled correctly,
understanding the issues of the firing order, they can be used. But why
would you choose to rely on a fragile, error-prone system that future
maintainers (including yourself!) may not understand when the code is
revisitted?
As there is a much simpler alternative (always use the ctor/dtor) I find
this a 'no-brainer', just do it. I'm not interested in picking through
the subtleties and details of a bug I never plan on fixing!
The OnShow is a little more annoying, as I use this frequently. The
issue only arises here is the 'Visible' property is set to true at
design time, as only then will 'Show' be called before construction. As
I always call show myself, I don't have a problem with this but it is
important to be aware of the problem. I find it a lot less subtle than
the OnCreate issue though and so can live with it.
AlisdairM
IMO, nothing. Anything that you think would go here should be in the
constructor. Pretend that FormCreate is really "BugInsert."
> What happened to cause the creation of such an idiotic thing?
VCL was written in OP for Delphi, where I've been told the FormCreate
method actually works.
> Also, what, if anything, comes between my constructor call,
> FormCreate, and FormShow?
FormShow is also unsuitable for initialization, and it can also run
prior to your constructor code. Also note that FormShow can be called
more than once during the life of the form, wich could be disaster if
you initialize anything here.
> Is there any place that I can reliably have access to a virtual
> function before FormShow is called?
I don't think so, but I don't really think that this is an issue. You
can call virtual methods from your constructor, though this may not be
prior to the first time your FormShow code runs, it will be prior to the
actual display of the form.
- Leo
> Ok, I've read all the newsgroups about not relying on FormCreate for form
> and property initialization. If someone can, please explain exactly what
> FormCreate is for??? If I cannot rely upon exactly when this closure is
> called, what can I rely upon it for? Note that I have several (some rather
> large) projects that have been brought up from BCB1 to BCB3, and now to
> BCB5. This OldCreateOrder business is a bit unbelievable, and I can only
> shake my head in wonder at what it could all possibly be for... What
> happened to cause the creation of such an idiotic thing?
My opinion is that the OnCreate event is a good thing for Delphi, and
since Delphi and BCB share the VCL it is inevitably exposed in the BCB
code as well.
However, my personal belief, based on my own design rules and safety
constraints, force me to conclude that the OnCreate event is not fit
for using ever in the C++ world. Some people will always continue to
use it, but if I had my way it wouldn't exist. (But I'm also very
restrictive on what I allow into my code, the pickier the better
IMHO.)
Anyway, even if it works for you, consider moving the code into the
constructor if that can be done appropriately. You'll be glad you
did, and then you can forget the OldCreateOrder nonsense.
--
Chris (TeamB);
You're the second person to suggest this approach, and it seems the best
solution to my problem that I've seen so far. I am rather amazed that there
is not a better way to do this...
Now, if you will excuse me, I have to go and write a *lot* of Loaded fn's...
Ken
"Matt Lee" <nos...@nospam.com> wrote in message news:3a77992a$1_2@dnews...
Yeah, I actually agree with you here -- I tend to be a bit BCB-centric
(especially when I rant...)
> However, my personal belief, based on my own design rules and safety
> constraints, force me to conclude that the OnCreate event is not fit
> for using ever in the C++ world. Some people will always continue to
> use it, but if I had my way it wouldn't exist. (But I'm also very
> restrictive on what I allow into my code, the pickier the better
> IMHO.)
Agreed.
> Anyway, even if it works for you, consider moving the code into the
> constructor if that can be done appropriately. You'll be glad you
> did, and then you can forget the OldCreateOrder nonsense.
Good advice, thanks.
Ken
Thanks for the reply, but am I reading this correctly? Are you saying that
OnShow, too, can be called prior to the ctor finishing the class'
initialization? That makes no sense to me -- how can the form be told to
show prior to its underlying object's full initialization? Please say it
isn't so...
You are saying directly something that Alisdair mentioned in his response. I
will repeat my question from there: How can the form be told to show prior
to its underlying object's full initialization? Am I going nuts? This makes
absolutely no sense to me. None. If this is true, my confidence in VCL is
entirely shaken.
> > Is there any place that I can reliably have access to a virtual
> > function before FormShow is called?
>
> I don't think so, but I don't really think that this is an issue. You
> can call virtual methods from your constructor, though this may not be
> prior to the first time your FormShow code runs, it will be prior to the
> actual display of the form.
Unless something has changed, a class' vtable is not fully initialized until
the ctor returns. You can call a virtual function, but you will not get the
most-derived version of that function, but the local version belonging to
the class being constructed... I was hoping there was some way to initialize
a VCL class outside the ctor so that I had a viable vtable (and thus a
functional virtual hierarchy) to work with.
Ken
Sorry to say, but this is the case. In Delphi, a constructor can call a
virtual method overridden by a descendant. Consider the following source
code:
#include <iostream>
class X {
public:
X() { foo(); }
virtual void foo() { std::cout << "X::foo" << std::endl; }
};
class Y : public X {
public:
Y() : X() {}
virtual void foo() { std::cout << Y::foo" << std::endl; }
};
int main() {
X x;
}
This code will print X::foo in C++, but (when correctly translated to Object
Pascal), will print "Y::foo".
sm
> Unless something has changed, a class' vtable is not fully initialized until
> the ctor returns. You can call a virtual function, but you will not get the
> most-derived version of that function, but the local version belonging to
> the class being constructed... I was hoping there was some way to initialize
> a VCL class outside the ctor so that I had a viable vtable (and thus a
> functional virtual hierarchy) to work with.
This is one of the warts that happens to merged-language object
models. Some things just don't quite fit, but are there anyway. Some
things are broken but are not prevented. Some limitations are
introduced, and some new capabilities exist.
Yet another good reason to strictly separate the application logic
from its user interface layer. I let the VCL do its thing, and I do
as little in the VCL-world as possible. Once the data is entered,
it's converted into my internal format, and as far as my application
cares, there is no gui whatsoever, just an abstract interface that
represents the user IO. (This interface happens to be implemented in
terms of the VCL, but that's irrelevant to the code that uses the
interface.)
--
Chris (TeamB);
I have been remiss... These are things I should have known for some time
now. It never occurred to me that BCB would work this way, but I should have
taken the time to learn the details. Having said that, this information also
should be in bold, 20pt type in the help file, readme and manuals. This is
crazy...
Thanks, Chris, for taking the time to explain.
Ken
> I have been remiss... These are things I should have known for some time
> now. It never occurred to me that BCB would work this way, but I should have
> taken the time to learn the details. Having said that, this information also
> should be in bold, 20pt type in the help file, readme and manuals. This is
> crazy...
>
> Thanks, Chris, for taking the time to explain.
The worst part, IMHO, is if you double click on a form it takes you to
FormCreate. Doh! Thus, not even everyone at Borland seems to be in
agreement that this event should not be used. This is probably due in
part to the strong Delphi culture at Borland (and somebody probably
didn't realize the ramifications.)
But I've submitted a feature request for the IDE to change the
behavior such that double clicking on a form brings you to the
constructor instead of FormCreate.
--
Chris (TeamB);
> Thanks for the reply, but am I reading this correctly? Are you saying that
> OnShow, too, can be called prior to the ctor finishing the class'
> initialization? That makes no sense to me -- how can the form be told to
> show prior to its underlying object's full initialization? Please say it
> isn't so...
Sorry I'm a couple of days replying, but just to add to all the other
comments...
When you create an instance of a form, a datamodule or most anything
else that uses the Delphi streaming mechanism all the properties will be
streamed as part of the VCL-base class behaviour. So when you invoke
the base-class constructor in the initializer list, that all happens
then.
The implication is that any properties that get set may also invoke
their associated events. The classic example is the Visible property of
a form invoking the OnShow method if set to true. For this reason, I
always set the design-time property to false. I'm sure there are other
examples too, so being aware of the cause will help you identify when
you hit them.
As mentioned before, this is the problem of trying to share an Object
Pascal library in a C++ environment. Some of the language conventions
appear plain odd, and can cause problems unforeseen in the original
environment.
For the flip side, try explaining the 'OldCreateOrder' property to a
Delphi developer...
AlisdairM
I am far from an expert on the internals of VCL - I've never even tried
to learn to read OP code and I get totally confused if I try to think
about the differences in construction sequences between OP and C++ and
their possible consequences on my programs - but I have some practical
experience in _using_ VCL in my programs. I'm not certain that FormShow
actually does show the form - I believe it is an event handler that is
called in response to a WM_SHOW message, so what it does is prepare for
the form to be shown. If you call ShowWindow(), then FormShow is
called, but it can also be called like any other function, and is often
called before code in the contructor is executed.
> Unless something has changed, a class' vtable is not fully initialized
> until the ctor returns. You can call a virtual function, but you will
> not get the most-derived version of that function,
Don't know all of the details, but remember that much of this is done in
OP, so it's different from straight C++. Personally I believe this to
be a _huge_ mistake on the part of Borland - I think Builder would be
able to grab a significant if not majority of the VC++ market if it had
a pure C++ VCL and a more stable IDE/project manager.
> I was hoping there was some way to initialize a VCL class outside
> the ctor so that I had a viable vtable (and thus a
> functional virtual hierarchy) to work with.
I'm not really sure what you are trying to do (in a practical sense)
here, but I would suggest that you put aside your theoretical musings
and just try initializing what you need initialized in the constructor.
What I have found is that that usually works. For many years, I've
programmed using OWL, and much of the initialization needed to be put
into the SetupWindow() method which reliably ran after the constructor.
When I first used VCL I assumed that the FormCreate() method would
provide the same services. I soon realized that this did not work, but
that if I shoved all of the code I felt belonged in FormCreate() into
the constructor all worked as intended.
- Leo