Why doesn't OnUpdate trigger for invisible components [duplicate]
Asked Answered
M

4

2

When I make a component invisible by setting the connected TAction to invisible, the onupdate event will not trigger anymore. To recreate, do the following.

  1. Create a new VCL forms application
  2. Drop a button, a checkbox and an actionlist on the form.
  3. Create a new action, and connect the button to it.
  4. Write the following code for the actions OnExecute and OnUpdate event:

    procedure TForm1.Action1Execute(Sender: TObject);
    begin
      ShowMessage('Test');
    end;
    
    procedure TForm1.Action1Update(Sender: TObject);
    begin
      TAction(Sender).Enabled := not CheckBox1.Checked;
      TAction(Sender).Visible := TAction(Sender).Enabled;
    end;
    

Run the application. The button is visible, and works properly. Check the checkbox, and the button disappears. Uncheck the checkbox. The button doesn't appear. In fact, if you put a breakpoint in Action1Update, you'll never get to it. Why is this, and how do I fix it?

Malamud answered 9/12, 2011 at 14:44 Comment(1)
There are better answers to this question at #10128185Aorangi
C
2

No need to fix this, it works as designed. Only visible controls need to update their state, so only actions whose linked controls are visible are updated. When you hide the button there's no more reason to update the action.

Comber answered 9/12, 2011 at 14:53 Comment(6)
So the only solution is to not set it invisible? In my case, there are some buttons I would like to make invisible rather then unabled when certain conditions are met. When these conditions chage, i would like to make the button visible again. I can do this manually, but I would prefer to use the OnUpdate on actions.Malamud
You could probably update the action manually (by calling Action.Update;) in the checkbox's click handler.Comber
@TOndrej: That defeats the purpose of using Actions though.Gollin
Use the OnUpdate Handler of the actionlist that holds the actions... Just make sure that it has at least one action that is linked to a visible control. (And don't forget to set Handled := True; or your handler will be called way too many times).Levitus
It doesn't defeat the purpose of using actions, @Afrazier. The purpose of using actions is to separate the UI from the business logic. Calling Action.Update doesn't affect that. Whoever calls Update doesn't have to know which controls are attached to the action. It somewhat defeats the purpose of the OnUpdate event, though, since this means there are some updates an action can do to itself that effectively cut itself down at the knees.Dar
Interesting comments, but I still don't see why this is done. I would think that it's quote normal to want to hide a button/menuitem/whatever, rather than disabling it, depending on the design of the user interface. Buttons get disabled and then enabled all the time, why shouldn't they be made invisible, then visible also? I will call this a bug, unless someone gives me a good reason not to :)Malamud
C
1

Have the OnUpdate only call a separate routine that does what is required. Then you can call that routine from other places. Action lists were designed for that.

Cassaba answered 9/12, 2011 at 15:36 Comment(0)
T
1

I understand what you're trying to do, and it makes sense that you would want it to work that way. However, here's a workaround for the way it does work.

You can update other controls in an OnUpdate also. You're not limited to updating the control that receives the notification. So, in the action for the control that determines visibility, you can set the visibility of the other controls there. In your case, that's the checkbox:

Create a new action (Action2) and assign it to Checkbox1.

Then in the checkbox action's OnUpdate:

procedure TForm1.Action2Update(Sender: TObject);
begin
  Button1.Visible := TAction(Sender).Checked;
end;

Be sure to assign an OnExecute to the checkbox as well. Something as simple as this is fine:

procedure TForm1.Action2Execute(Sender: TObject);
begin
  TAction(Sender).Checked := not TAction(Sender).Checked;
end;

To me, this still makes logical sense. You'll be able to look in one spot to see all of the controls whose visibility relies on that checkbox being set.

Tiresome answered 9/12, 2011 at 20:0 Comment(0)
S
1

You can override the InitiateAction method on the form. This will happen whenever the application goes idle, just as on OnUpdate event does for each action.

Singlecross answered 6/3, 2013 at 0:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.