Hello, my name is Button1
The name of a component plays a fundamental role in
Delphi and C++Builder, but some of the features behind this
property are far from well-known.
Name and Tag are published properties defined in the
TComponent class. They are both available for each and every
VCL component. Tag is there for your own personal use -- the
VCL never refers to it -- but the Name property plays a very
special role. As I hope to show you in this article, the Name
property has a variety of subtle, largely unexplored aspects.
Naming conventions
Delphi assigns names to components based on a simple
convention: the class name minus the first letter plus a
sequencer number that distinguishes components of the same
type within the same form (or other component container, such
as a frame or data module).
The first rule for the Name property is to give readable
names to the components as soon as possible. Techniques range
from adapted Hungarian notation, with the type prefacing the
component role (btnAdd) to minor changes to the
generated names (ButtonAdd), to names indicating only
the role and not the type (Add). I don't like this last
notation, though many of the demos that ship with Delphi use
it. I prefer the first sort of name. Your mileage will almost
certainly vary; there are as many variations on naming
conventions as there are Delphi programmers.
It would be nice if Delphi generated names in a
user-configurable way, so we could ask the IDE to use btn
as initial portion of the name generated automatically for
any new TButton object.
Whatever you choose, give your components a name before
writing code the code that refers to them, as Delphi doesn't
fix component references retroactively. Delphi fixes
references from one component to another and updates the names
of event handlers (a Button1Click will become btnAddClick).
When assigning a name, remember that it must be a valid Pascal
identifier; no spaces or special characters are allowed. Every
name must start with a letter or underscore followed by other
letters, numbers or underscore characters.
My name, your name
Two components on the same form cannot have the same name.
If you rename Button2 as Button1 and a component with this
name already exists, the IDE will flag an error. Even when you
create components at runtime, their names must be unique. This
rule is enforced by an ownership mechanism: All the components
owned by a single class must have unique names. By the way,
this makes it possible to apply to an owner the FindComponent
method, passing the name of a component as parameter.
There is an exception to this rule: You can have multiple
components with the same name as long as Name is set to an
empty string. In this case there is no conflict, but also no
way to find the components by name. If you blank out the Name
property of a component at design time, Delphi will remove the
corresponding field from the form class declaration. The field
can also be removed manually in the source code, in this case
without affecting the component name.
At runtime, you might want to create unnamed components to
avoid the minor hassle of generating unique names. At design
time, you might want to remove the names to save space in
memory and reduce the size of the executable file for all the
components you'll never refer to, from menu item separators to
fixed labels. The only rule is to keep the name of at least
one component of each type. This will help you avoid problems
with the Delphi linker and RTTI.
Of components and fields
As the Delphi help files point out, the Name property
"specifies the name of the control as referenced in code."
This means that in the source code we can refer to a component
by using its name. But this is a simplistic view. The Name is
a string, part of the component. When you type Button1 in the
source code you are referring to a field of a form class. How
do they relate? At design time, changing the name results in
changing the field name as well. At runtime changing the name
can result in disaster.
When Delphi creates a form it reads the corresponding DFM
file embedded in the resources of the application, creating
the specified components and reassigning the streamed
properties. While setting the component Name from the DFM
file, the component looks into the published fields of its
owner using TObject's FieldAddress method and assigns itself
to the corresponding field, if any. If you want to look up
this code in the VCL source, the field connection takes place
in the private SetReference method of TComponent, called by
SetName.
This code is not specifically related to streams, but is
executed every time you call the SetName method by assigning a
new value to the Name property at runtime. SetName calls
SetReference twice, first to disconnect the current component
from the field and second to connect it to a new field
corresponding to the new name. So by assigning a new name to a
component at runtime the original form field (your usual
reference to the component in the source code) will generally
be set to nil. A simple assignment like:
Button1.Name := 'new';
will cause any further reference to Button1 to produce an
access violation!
The Delphi help file warns us to change control names only
at design time but gives no clue why this is sound advice.
Although I don't recommend it as a common practice, the truth
is that the name can be changed at runtime. (Technically, the
warning refers to the Name property of the TControl class, not
the TComponent class. But the only difference between the two
classes is that controls with a special style active change
their captions along with the names, assuming the two match.)
This analysis reveals why form fields referring to components
must be published. Were the fields corresponding to components
private, the corresponding objects would not be able to find
them and attach themselves to the fields.
What's in a Name?
The Name property performs a lot of magic behind the
scenes, as it identifies a component within its owner and
connects it to the owner field. The value of the name property
and the form field generally match, but do not confuse them --
they are separate. Strangely enough, the compiler name of a
four-byte pointer and a string saved within an object look for
each other and merge so well to become almost
undistinguishable to users...but not to an expert eye.
Originally written for InPublishing LLC for publication by Inprise Corp. Copyright 1999 Inprise Corp.
|