Marco's Web Center
Menu for Development
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.
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:
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.
|© Copyright Marco Cantù, 1995-2014, All rights reserved|