In VCL Forms applications, the form is the ultimate container for components. Besides the form, Delphi provides several other components that are able to contain other components. These components are also known as container components. Standard container components are TGroupBox and TPanel in the Standard category, TScrollBox in the Additional category, and TPageControl in the Win32 category.
Components are usually grouped for two reasons. At design time, component groups increase productivity because we can treat a group of components as a single unit. At run time, groups improve the quality of the user interface. Some container components, like TGroupBox, also improve the visual appearance of the application. For instance, the Project Options dialog box uses the TGroupBox component to group related options together. The Code generation, Syntax options, Runtime errors, and Debugging frames visible in the dialog box are TGroupBox components that contain several check boxes each (see Figure 11-20).
Figure 11-20: TGroupBox components in the Project Options dialog box
The best way to add child components to a container component is to first add the container component to the Designer Surface. When you add components to the Designer Surface, they are added to the container component under the mouse cursor. If there are no additional container components on the Designer Surface, the components are added to the form. When you have several container components on the form, the Structure window becomes an invaluable tool (see Figure 11-21).
Figure 11-21: Parent-child relationships on the form
The components that you work with at design time are real object instances. When you add a component from the Tool Palette window to the Designer Surface, the IDE calls the appropriate constructor to create an object instance.
The component constructor differs from the standard object constructor. The component constructor has a TComponent parameter:
constructor Create(AOwner: TComponent);
The AOwner parameter is used to define the owner of a component. The Owner component is responsible for freeing the memory occupied by the components it owns. When you design applications in the Delphi IDE, the form is automatically assigned as the owner of all components.
If you want to verify this, drop a button on the Designer Surface and write the following line in the OnClick event handler:
procedure TForm1.Button1Click(Sender: TObject); begin Caption := 'The Owner of Button1 is ' + Button1.Owner.Name; end;
While components only have the Owner property, controls (components derived from the TControl class) have both the Owner and Parent properties. The parent control is responsible for displaying the control onscreen. All container controls can be parents. If you add a component to the form, the form is both the owner and the parent. If you add the component to a container control like TPanel, the TPanel component becomes the Parent component.
To verify this, let's add a TPanel to the form and move the button to the TPanel. You can change the button's parent at design time by using the clipboard or the Structure window. To do so using the clipboard, do the following:
Select the button and cut it to the clipboard using Edit ® Cut.
Select the panel component on the Designer Surface.
Use the Edit ® Paste option to add the previously cut button to the panel.
The Structure window provides an even easier way of moving the button to the panel — simple drag and drop.
Figure 11-22: Changing the component's parent at design time
Now that the button is located on the panel, we can, for instance, use the ShowMessage procedure to display the names of the Parent and Owner components. The ShowMessage procedure is a very simple message that accepts a single string parameter and displays a message box with an OK button (see Figure 11-23). The ShowMessage procedure is declared in the Dialogs unit.
Figure 11-23: Displaying parent and owner information
Listing 11-3: Displaying parent and owner information
procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage('Owner: ' + Button1.Owner.Name); ShowMessage('Parent: ' + Button1.Parent.Name); end;
The final note about container components concerns memory usage. Container controls are really useful and irreplaceable when it comes to grouping components, but they aren't meant to be used extensively as graphical decorations on the form.
For instance, the TPanel component is often used to create a frame around a group of components. With the BevelInner property set to bvRaised and the BevelOuter property set to bvLowered, the panel displays a beveled border. If you need the frame but don't need the container functionality of the TPanel component, you should use the TBevel component.
The TBevel component is a graphical component that can't contain other components and uses fewer system resources than the TPanel component. The TBevel component has only one purpose — to display a beveled frame on the form. To display the frame on the form, set the TBevel component's Shape property to bsFrame (see Figure 11-24). You can find the TBevel component in the Additional category on the Tool Palette window.
Figure 11-24: TPanel and TBevel frames
If you add a TBevel component to the form after you have added the components you wish to frame, the TBevel component will have a higher Z order and you won't be able to access the components "beneath" it. To access components beneath the TBevel component, right-click the TBevel component and select Control ® Send To Back from the context menu.