• No results found

Control-Related Techniques

In document Mastering Delphi 7 (Page 177-181)

After this general overview of the most commonly used Delphi controls, I'll devote some space to discussing generic core techniques not related to a specific component. I'll cover the input focus, control anchors, the use of the splitter component, and the display of fly-by hints. Of course, these topics don't include everything you can do with visual controls, but they provide a starting point for exploration to get you up and running with some of the most common techniques.

Handling the Input Focus

Using the TabStop and TabOrder properties available in most controls, you can specify the order in which controls will receive the input focus when the user presses the Tab key. Instead of setting the tab order property of each component of a form manually, you can use the shortcut menu of the Form Designer to activate the Edit Tab Order dialog box, shown in Figure 5.6.

Figure 5.6: The Edit Tab Order dialog box

Besides these basics settings, it is important to know that each time a component receives or loses the input focus, it receives a corresponding OnEnter or OnExit event. This allows you to fine-tune and customize the order of the user operations. Some of these techniques are demonstrated by the InFocus example, which creates a typical

password-login window. Its form has three edit boxes with labels indicating their meaning, as shown in Figure 5.7. At the bottom of the window is a status area with prompts guiding the user. Each item needs to be entered in sequence.

Figure 5.7: The InFocus example at run time

For the output of the status information, I've used the StatusBar component, with a single output area (obtained by setting its SimplePanel property to True). Here is a summary of the properties for this example. Notice the & character in the labels, indicating a shortcut key, and the connection of these labels with corresponding edit boxes (using the FocusControl property):

object FocusForm: TFocusForm ActiveControl = EditFirstName Caption = 'InFocus'

object Label1: TLabel Caption = '&First name' FocusControl = EditFirstName end

object EditFirstName: TEdit OnEnter = GlobalEnter OnExit = EditFirstNameExit end

object Label2: TLabel Caption = '&Last name' FocusControl = EditLastName end

object EditLastName: TEdit OnEnter = GlobalEnter end

object Label3: TLabel Caption = '&Password' FocusControl = EditPassword end

object EditPassword: TEdit PasswordChar = '*' OnEnter = GlobalEnter end

object StatusBar1: TStatusBar SimplePanel = True

end end

The program is simple and performs only two operations. The first is to identify, in the status bar, the edit control that has the focus. It does this by handling the controls' OnEnter event, using a single generic event handler to avoid repetitive code. In the example, instead of storing extra information for each edit box, I've checked each control of the form to determine which label is connected to the current edit box (indicated by the Sender parameter):

procedure TFocusForm.GlobalEnter(Sender: TObject);

var

This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks.

I: Integer; (TLabel(Controls[I]).FocusControl = Sender) then // copy the text, leaving off the initial & character StatusBar1.SimpleText := 'Enter ' +

Copy (TLabel(Controls[I]).Caption, 2, 1000);

end;

The form's second event handler relates to the first edit box's OnExit event. If the control is left empty, it refuses to release the input focus and sets it back before showing a message to the user. The methods also look for a given input value, automatically filling the second edit box and moving the focus directly to the third one:

procedure TFocusForm.EditFirstNameExit(Sender: TObject);

MessageDlg ('First name is required', mtError, [mbOK], 0);

end

elseif EditFirstName.Text = 'Admin' then begin

// fill the second edit and jump to the third EditLastName.Text := 'Admin';

EditPassword.SetFocus;

end;

end;

Tip The CLX version of this example has the same code and is available as the QInFocus program.

Control Anchors

To let you create a nice, flexible user interface, with controls adapting themselves to the current size of the form, Delphi allows you to determine the relative position of a control with the Anchors property. Before this feature was introduced in Delphi 4, every control placed on a form had coordinates relative to the top and bottom, unless it was aligned to the bottom or right side. Aligning is good for some controls but not all of them, particularly buttons.

By using anchors, you can make the position of a control relative to any side of the form. For example, to anchor a button to the bottom-right corner of the form, you place the button in the required position and set its Anchors property to [akRight, akBottom]. When the form size changes, the distance of the button from the anchored sides is kept fixed.

In other words, if you set these two anchors and remove the two defaults, the button will remain in the bottom-right corner.

On the other hand, if you place a large component such as a Memo or a ListBox in the middle of a form, you can set its Anchors property to include all four sides. This way the control will behave as an aligned control, growing and shrinking with the size of the form, but there will be some margin between it and the form sides.

Tip Anchors, like constraints, work both at design time and at run time. You should set them up as early as possible, to benefit from this feature while you're designing the form as well as at run time.

As an example of both approaches, you can try the Anchors application, which has two buttons in the bottom-right corner and a list box in the middle. As shown in Figure 5.8, the controls automatically move and stretch as the form size changes. To make this form work properly, you must also set its Constraints property; otherwise, if the form becomes too small, the controls can overlap or disappear.

Figure 5.8: The controls of the Anchors example move and stretch automatically as the user changes the size of the form. No code is needed to move the controls, only proper use of the Anchors property.

Notice that if you remove all the anchors or two opposite ones (for example, left and right), the resize operations will cause the control to float in the form. The control keeps its current size, and the system adds or removes the same number of pixels on each side of it. This anchor can be defined as centered, because if the component is initially in the middle of the form it will keep that position. If you want a centered control you should generally use both opposite anchors, so that if the user makes the form larger, the control size will grow as well. In the case just presented, making the form larger leaves a small control in its center.

Using the Splitter Component

There are several ways to implement form-splitting techniques in Delphi, but the simplest approach is to use the Splitter component, found in the Additional page of the Component Palette. To make it more effective, the splitter can be used in combination with the Constraints property of the controls it relates to. As you'll see in the Split1 example, this technique allows you to define maximum and minimum positions for the splitter and the form. To build this example, simply place a ListBox component in a form; then add a Splitter component, a second ListBox, another Splitter, and finally a third ListBox component. The form also has a simple toolbar based on a panel.

By simply placing these two splitter components, you give your form the complete functionality of moving and sizing the controls it hosts at run time. The Width, Beveled, and Color properties of the splitter components determine their appearance, and in the Split1 example you can use the toolbar controls to change them. Another relevant property is MinSize, which determines the minimum size of the form's components. During the splitting operation (see Figure 5.9), a line marks the final position of the splitter, but you cannot drag this line beyond a certain limit. The behavior of the Split1 program is not to let controls become too small. An alternative technique is to set the new AutoSnap property of the splitter to True. This property will make the splitter hide the control when its size goes below the MinSize limit.

This document was created by an unregistered ChmMagic, please go to http://www.bisenter.com to register it. Thanks.

Figure 5.9: The Split1 example's splitter component determines the minimum size for each control on the form, even those not adjacent to the splitter.

I suggest you try using the Split1 program, so that you'll fully understand how the splitter affects its adjacent controls and the other controls of the form. Even if you set the MinSize property, a user can reduce the size of the program's entire form to a minimum, hiding some of the list boxes. If you test the Split2 version of the example, you'll get better behavior. In Split2, I've set some Constraints for the ListBox controls:

object ListBox1: TListBox Constraints.MaxHeight = 400 Constraints.MinHeight = 200 Constraints.MinWidth = 150

The size constraints are applied only as you resize the controls; so, to make this program work satisfactorily, you have to set the ResizeStyle property of the two splitters to rsUpdate. This value indicates that the controls' position is updated for every movement of the splitter, not only at the end of the operation. If you select the rsLine or the new rsPattern value, instead, the splitter simply draws a line in the required position, checking the MinSize property but not the constraints of the controls.

Tip When you set the Splitter component's AutoSnap property to True, the splitter will completely hide the neighboring control when the size of that control is below the minimum set for it in the Splitter component.

In document Mastering Delphi 7 (Page 177-181)