5

I have a TAction that is used for both a menu item and a TButton. I want the menu item to show the label, and the TButton to show only the icon. However, when an Action is assigned, Vcl automatically sets the TButton's Caption attribute, and I cannot get rid of it.

Any ideas?

Hendrik
  • 569
  • 3
  • 12

3 Answers3

6

On the menu item, set ImageIndex to -1. On the button, set the Caption to ''. You must do this at runtime.

This will break the association with the action for just those individual properties. The action will still be used for Hint, OnExecute, OnUpdate etc.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
4

You could have two separate actions: one for the menu item, one for the button.

Ondrej Kelle
  • 36,941
  • 2
  • 65
  • 128
  • 3
    It is a possibiliy, but it ignores the principle of actions. – GolezTrol Dec 11 '12 at 10:02
  • 1
    @GolezTrol I don't think so. For example, they could both share the same handlers for `OnExecute` and `OnUpdate` events. – Ondrej Kelle Dec 11 '12 at 10:14
  • 2
    Yes, a Button and a MenuItem could share an OnClick handler as well. The principle of action is to define a piece of code, without caring about which control or controls execute them. You want (amongst others) to be able to disable just that action, not having to worry about other actions doing the same thing. – GolezTrol Dec 11 '12 at 11:07
  • 1
    Yes, and there's no conflict with any "principle of actions". If two or more actions share the same `OnExecute` and `OnUpdate` handlers you still don't care which control executes them. You can (amongst others) disable just those actions, in one place, in the shared `OnUpdate` handler and don't have to worry about anything. – Ondrej Kelle Dec 11 '12 at 11:15
  • 2
    A slight variation of TOndrej's technique is to layer the two actions. Proceed as TOndrej's suggestion of two actions - one for the button and one for the menu item, but consider one action to be 'higher' than the other. Instead of directly sharing event handlers, let the higher action's event handler invoke the lower one. In an immediate sense, the outcome is the same. But it gives you one more degree of separation, offering cheaper extensibility. – Sean B. Durkin Dec 11 '12 at 12:18
  • Actually, having two actions that do the same thing _does_ break the principle of actions. When you enable/disable actions in the TActionList's OnUpdate handler (as you should), you now have two actions to worry about instead of one. If you would like more info on why and how you should use the TActionList's OnUpdate handler, check out Ray Konopka's (yes, author of the Raize components) excellent article on them: [Effectively using Action Lists](http://edn.embarcadero.com/article/27058) – Marjan Venema Dec 11 '12 at 18:49
  • @MarjanVenema It's not clear from your comment what you mean by "principle of actions" and how this breaks it. BTW, I don't agree with your assertion that one *should* use `TActionList`'s `OnUpdate` handler. I agree with Ray that sometimes it may be easier to manage, depending on the application context. – Ondrej Kelle Dec 11 '12 at 23:50
  • @TOndrej: principle of actions in my mind = one TAction manages the visibility, enabledness etc. of a single user action. Ok, 'should' may be a bit strong, but I have found that concentrating the logic for what's available through the user interface in one handler greatly improves manageability and maintainability of the interrelationships of all user actions. – Marjan Venema Dec 12 '12 at 07:00
  • @MarjanVenema Well, based on that definition, I agree with you, this breaks it. ;-) Thanks for taking the time to explain it. – Ondrej Kelle Dec 12 '12 at 08:26
3

A more hacky solution could be setting the TAG 22 to e.g. in following Example

type

  TButton=Class(Vcl.StdCtrls.TButton)
         procedure SetText(var Message:TWMSETTEXT); message WM_SETTEXT;
  End;

  TForm4 = class(TForm)

    ActionList1: TActionList;
    ImageList1: TImageList;
    Action1: TAction;
    BitBtn1: TBitBtn;
    Button1: TButton;
    Button2: TButton;
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

{ TMyButton }

procedure TButton.SetText(var Message:TWMSETTEXT);
begin

  if Tag<>22 then   inherited else Message.Result := 1;
end;
bummi
  • 27,123
  • 14
  • 62
  • 101
  • I'm not sure I would use this hacky method, but I like the principle of making the button handle the text property differently. A cleaner alternative would be to use some kind of a TIconButton that only displays the image and uses the Text property as a hint (or not at all, since the Action has a hint as well). But in general, I think this is the best solution. – GolezTrol Dec 11 '12 at 10:04