Title: Actions that live in Delphi.
Question: Actions, what's good in them what are they for.
Answer:
Actions came in view in Delphi in version 4.0 and to say the truth I did not think that this was something really helpful and interesting then. You know you seldom want to improve something that already works fine and since my programs worked fine without actions I was not so excited about them then. I am now!
So what is so good about them anyway? The answer is as simple as the word EVERYTHING. The article you are reading is not intended to be the complete source of the information. I just will give you few examples and point out few ways where actions can be of help so you can decide for yourself if you really want to use all advantages they are ready to give you.
Advantage #1
Suppose you created some utility. You have implemented all the functionality you wanted and the only your concern now is to give the customer an easy way to exit your program. Obviously you have some menu that contains Close item which once clicked terminates the program execution. But you decided to add one more option for your customer and placed a button with the same functionality somewhere on your form. Then you added some code and finally you have two routines:
//menu item
procedure TForm1.Close1Click(Sender: TObject);
begin
Close;
end;
//button
procedure TForm1.Button1Click(Sender: TObject);
begin
Close;
end;
Good isnt it? Now what would it look like with the actions? Add one TActionList component. Now activate its component editor. Either double click on the component or select Action List Editor from the component popup menu. Once you are inside the editor add one TAction component. You can:
1. Hit Insert key.
2. Click tool button with appropriate hint.
3. Select appropriate item from the editors popup menu.
Now select newly added action and set its Caption property (in Object Inspector) to Close. Then add OnExecute event handler:
procedure TForm1.Action1Execute(Sender: TObject);
begin
Close;
end;
All you need to do now is to assign Action properties of our two components (menu item and button) to the TAction component we have just created. Do note that once Action is assigned both button and menu item have caption Close.. Also look where OnClick event of the components is pointing to now.
So what? you can say, Not a big deal. I could live without these actions at least till 1/1/3000.. Well on this stage yes. However even in this small example we now have one routine instead of two and our code is more readable. I could also tell you that not only our PAS file is smaller now but our DFM as well. How come? I will explain that later. Anyway imagine that you use owner drawn menu instead of the normal one and TBitBtn instead of TButton, and both components have the glyphs. Without actions you would need to assign THE SAME image to both controls, so you would have to put the same bitmap into your resources twice. Since bitmaps are sometimes really big that can be serious economy.
Now one more reason why we have smaller DFM files with the actions. See how Caption property is declared in TControl:
property Caption: TCaption read GetText write SetText stored IsCaptionStored;
and here is that IsCaptionStored procedure:
function TControl.IsCaptionStored: Boolean;
begin
Result := (ActionLink = nil) or not ActionLink.IsCaptionLinked;
end;
In other words caption of our button control (and the same with menu item) is stored in the DFM only if there is no Action assigned. If there is an Action then we save Caption assigned to TAction only. Now all the controls that are linked to this Action (no matter how many of them you have) will use the same caption saved only once. Keep in mind that TAction has another properties such as:
Caption,
Checked,
Enabled,
HelpContext,
Hint,
ImageIndex,
ShortCut,
Visible
apart from Caption and that with TActionList we can use just one TImageList for all the controls... Well, this is quite an economy.
Advantage #2
Now for some more. Suppose you have another form that displays some info for your users and you want this info to be available for registered users only. You perform some checking and if you found out that this copy of the program is used by a registered user you enable appropriate button and menu item, otherwise you disable them:
begin
InfoMenuItem.Enabled := ISRegisteredUser;
InfoButton.Enabled := ISRegisteredUser;
end;
With Actions the above code looks as follows:
begin
Action1.Enabled := ISRegisteredUser;
end;
This time the advantage is not the fact that you produce more compact code, the real kick is that you are modifying state of two controls in one line without calling any methods or modifying any properties of these controls directly! When you update Enabled state of the Action all involved controls and components are automatically updated accordingly.
Advantage #3
How about standard actions? You would like to create Window menu and just dont know what items should appear there and how to implement these Tile, Cascade and other commands? Really how? No problem, all you have to do is to create TActionList component, activate its component editor and pick up Create Standard Action command from the toolbar (or from the popup menu) there. You will see the list of items then where you will have to select those related to category Window and add all or just necessary standard Window commands. The good news #1 - once you created and assigned menu items to these actions you do not need to write any code for OnExecute. Everything has already been written. Good news #2 - if you created and assigned TImageList, it will contain all necessary images for the Actions that you have just added.
Advantage #4
Now the last but not the least. You can plan and create well-organized projects with the Actions. For example create TCustomModule and there TActionList and that will be the heart of your application. All events and code will be placed there. Then you add the name of this unit to the uses section of all other units (you might want to do it in implementation section to avoid circular reference problem) and you can assign Action property of your visual controls to the Actions created in your custom module.
Every TAction descendant has the Category property. It is not going to be used in Run-Time but you may use it in Design-Time to organize your actions and make editor much easier to navigate and manipulate.
The only thing you should be aware of with the actions is the fact that components' published properties (those listed above) are not saved if there is an action assigned (I already explained why). Thus there is no reason to modify them. Plus if you use Actions it is a bad style to access properties of the control directly. You can never tell (actually you can but ;-) when they are overridden by the values that Actions' properties have.
One more limitation is that any standard action can only be used with those controls' events that have exactly one parameter - (Sender: TObject). That means you can not create Action for OnMouseMove or OnKeyDown event of a form (but still can for OnActivate or OnClose).
Ok thats about all I can say in regard to these pretty Actions and what gain they can make for you and your applications. One more important thing about them is of course that you can create and register your own Action types with the required functionality and parameters list. But as they say thats for another story.
Artem A. Berman