Delphi 4 - Fun with Delphi 4 - Toolbars and Controlbars

By: John Kaster

Abstract: What I Learned from Customer Reactions to Delphi 4 at PC Expo

Fun with Delphi 4
Or, "What I Learned from Customer Reactions to Delphi 4 at PC Expo"
John Kaster
Enterprise Product Manager, Inprise Corporation

Toolbars and ControlBars
You can place any Delphi visual component on a TControlBar, which will automatically contain it in a toolbar, allowing you to move it around the ControlBar. Toolbars have also been enhanced to support docking and undocking. Since Delphi was written in Delphi and it uses its own VCL components to provide the interface for the IDE, practically all of the things you see in the IDE can be implemented in your own applications. You can even make your applications look like Microsoft Office applications, if that's familiar to your end users. Delphi 4 also has support for the new Microsoft Windows 98/Internet Explorer 4 controls, the IntelliMouse wheel, and enhanced Win95 control support.

Compare the following screenshot to the previous one of the "Best Windows" form. Notice the toolbars have been moved around, and the ControlBar (the panel containing the ToolBars) has actually grown to accommodate my dragging the "Windows" button toolbar down. If I wanted to, I could set a toolbar's DragKind to be dkDock and its DragMode to be dmAutomatic and drag any toolbar off the main form and leave it somewhere else on the desktop while the application is running.

Toolbars Moved Around
Click here to view full size image.

Two of the toolbars in this ControlBar were automatically created by simply dragging the Button (for the "Windows" button) and the DateTimePicker (currently active and overlapping the graph) onto the ControlBar. Then I was able to move each control anywhere I wanted on the ControlBar.

The ability to set a few properties and have this kind of visual flexibility and end-user control of the interface to an application is unprecedented. Demonstrating these features earned Delphi 4 much applause from all the developers in the audience.

Actions and Action Lists
Delphi 4 introduces a radically easy way to make your applications highly adaptive to the end user. ActionLists allow you to control the behavior of entire sets of components by setting up rules for handling all of them at one time. Here's a simple example that illustrates the point pretty well.

To make this demonstration shorter, I have an ImageList component with some images already contained in it. I created a component template for it by adding several images to the image list, then selecting component, and using the menu option Component|Create Component Template.

This application initially supports cutting and copying selected text to the Clipboard and pasting that text into another edit control. Now, we'll create the first phase of the ActionList application.

  • Set the form's Caption to "ActionList Demonstration"
  • Drop an ImageList on the form from the Win32 tab and add some images to it.
  • Drop an ActionList component (usually the last component on the Standard tab) onto the form and set its Images property to ImageList1.
  • Double click on ActionList1 to bring up its component editor.
  • Click on the down arrow to the right of the New button, and select the New Standard Action menu option.
  • Add the three standard edit actions to your ActionList. In the following screenshot, I have added the first two and am about to add EditPaste.

Adding Standard Edit Actions
Click here to view full size image.

After adding all three edit actions, I set the Action names to EditCopy, EditCut, and EditPaste and also assigned their ImageIndex properties to something appropriate from the image list.

We'll now use these Standard Actions with menu items and toolbar buttons.

  • Drop a MainMenu component from the Standard tab onto the form and double-click on it.
  • Set its Images property to ImageList1.
  • Set the caption for the main menu item to "&Edit"
  • Click on Edit in the menu designer and assign the Action property for the first submenu item to EditCopy. Notice that all the properties for the menu item are set to the values for the Action.
  • Add a submenu item and set its Action to EditCut.
  • Add a submenu item and set its Action to EditPaste.
  • The form should now look something like this when you click on the Edit menu option:

ActionList Demonstration

  • Drop a Toolbar from the Win32 tab on the form and set its Images property to ImageList1.
  • Invoke the Toolbar's popup menu with a right mouse click to add three new buttons to the toolbar.
  • Set the Action for the first button to EditCut.
  • Set the Action for the second button to EditCopy.
  • Set the Action for the third button to EditPaste.
  • Drop two Edit controls onto the form.

Run the application. Use the mouse to select and unselect text from either of the edit controls and watch the buttons on the toolbar. Notice the Copy and Cut buttons are not enabled unless text is selected in one of the edit controls. If your Windows Clipboard does not currently contain text, the Paste button will also be disabled until you cut or copy text into the Clipboard. Here are three screenshots side by side. The captions beneath the screenshots explain why the buttons are enabled or disabled.

No text selected, nothing in clipboard
No text selected,
nothing in clipboard
Text selected
Text selected
Text selected
Clipboard has text,
no text selected

As you can see, there is intelligent behavior going on underneath the surface you don't have to program into your application anymore. Even better, ActionLists get examined by your application whenever the mouse goes idle, so there is no end-user perceivable delay to using the ActionLists. (Delphi is so fast anyway I doubt you'd notice, but you might as well design it right the first time.)

The way Actions and ActionLists are designed, the code to provide this intelligence is surprisingly simple. All three of these actions descend from a TEditAction class. Here is the relevant code to provide the user-adaptive behavior for the Edit Actions.

interface
...
TEditAction = class(TAction)
private
 FControl: TCustomEdit;
 procedure SetControl(Value: TCustomEdit);
protected
 function GetControl(Target: TObject): TCustomEdit; virtual;
 procedure Notification(AComponent: TComponent; Operation: 
   TOperation); override;
public
 function HandlesTarget(Target: TObject): Boolean; override;
 procedure UpdateTarget(Target: TObject); override;
 property Control: TCustomEdit read FControl write SetControl;
end;

TEditCut = class(TEditAction)
public
 uprocedure ExecuteTarget(Target: TObject); override;
end;

TEditCopy = class(TEditAction)
public
 procedure ExecuteTarget(Target: TObject); override;
end;

TEditPaste = class(TEditAction)
public
 procedure UpdateTarget(Target: TObject); override;
 procedure ExecuteTarget(Target: TObject); override;
end;
...
implementation
...
{ TEditAction }
function TEditAction.GetControl(Target: TObject): TCustomEdit;
begin
 { We could hard cast Target as a TCustomEdit since 
   HandlesTarget "should" be called before ExecuteTarget and 
   UpdateTarget, however, we're being safe. }
 Result := Target as TCustomEdit;
end;

function TEditAction.HandlesTarget(Target: TObject): Boolean;
begin
 Result := ((Control <> nil) and (Target = Control) or
 (Control = nil) and (Target is TCustomEdit)) and 
   TCustomEdit(Target).Focused;
end;

procedure TEditAction.UpdateTarget(Target: TObject);
begin
 if (Self is TEditCut) or (Self is TEditCopy) then
  Enabled := GetControl(Target).SelLength > 0;
end;

{ TEditCopy }

procedure TEditCopy.ExecuteTarget(Target: TObject);
begin
 GetControl(Target).CopyToClipboard;
end;

{ TEditCut }

procedure TEditCut.ExecuteTarget(Target: TObject);
begin
 GetControl(Target).CutToClipboard;
end;

{ TEditPaste }

procedure TEditPaste.ExecuteTarget(Target: TObject);
begin
  GetControl(Target).PasteFromClipboard;
end;

procedure TEditPaste.UpdateTarget(Target: TObject);
begin
Enabled := Clipboard.HasFormat(CF_TEXT);
end;

You can also make your own actions available to a specific application by using the ActionList editor to create custom actions. The status of those actions will also be updated whenever the mouse goes idle, so you should write them to determine their status as quickly as possible to prevent delays in the user interface.

Actions and ActionLists are ideal for developing a suite of highly friendly, flexible, and adaptive behaviors for all of your applications. If you can abstract the behavior for a certain type of component and its descendants, there is a very good chance that an Action could be the easiest way to reuse that behavior. If you're a chief designer or architect at your company, you could design actions that your more junior developers could then use in their specific applications, increasing their productivity and overall time-to-market for the entire application.

I anticipate that third parties will be releasing many sets of Actions as part of new offerings for their component libraries. It sounds to me like developing with Delphi 4 is going to be quite action-packed.

Native Delphi Internet Controls
These new components are the world's highest-performance suite of components implementing Internet standards, especially communications protocols. They are written in pure Delphi over the open WinSock standard, and are essential for professional Delphi developers building Internet-enabled desktop and client/server applications.


Server Response from: ETNASC03