5

I need to perform a long action with a button. I tried setting the DynamicEvaluationTimeout, but it seems it doesn't work for me. So I want to try using several buttons to compute pieces of the whole task and here's where my problem starts: How to tell Mathematica that a button should be pressed (or have its action performed) without actually pressing the button by user? Is there a way to emulate such a thing from within the code? I need to use the preemptive link, so Method -> "Queued" is not the solution I'm looking for.

István Zachar
  • 47,032
  • 20
  • 143
  • 291
Daroslav
  • 91
  • 4

1 Answers1

5

One can come up with some messy method to evaluate a front-end button programmatically, but I think it is easier to separate the button functionality from the button itself, as listenerButtonFunction[]. Here I introduce a timer button that, if pushed, counts down simulating a long calculation. When it finishes, it switches the flag active to True. The second button has a Dynamic wrapper and thus it listens to the changes made to active: whenever active is set to True, the appearance of the listener button is changed. Now the functionality of the listener button is separated, so we can call it right after setting active = True in the first button, simulating the manual push of the listener button.

Note that I only used Method -> "Queued" to see how the timer goes down. If omitted, the listener still will be activated in due time. Also, the listener button can be pushed on its own.

active = False;
n = 0;
listenerButtonFunction[] := Print["Listener activated"];
Row@{Button["Timer", active = False; n = 100; 
   Do[Pause[.02]; n = n - 1, {i, 100}]; active = True; 
   listenerButtonFunction[], Method -> "Queued"], Spacer@5, Dynamic@n}
Dynamic@If[active,
  Button["Listener: ACTIVE", active = False, 
   Appearance -> {Automatic, "Pressed"}],
  Button["Listener: inactive", listenerButtonFunction[], 
   Appearance -> Automatic]
  ]

enter image description here

Update

The following method creates a button that is wrapped in Dynamic that listens to the state change of the switch active, which can be changed by either hitting the second button or waiting for the calculation of the first button to finish (just like above). The function of this second button is actually performed by the Dynamic wrapper whenever active becomes True. The Print statement is redirected by default to the Messages window, but if listenerFunction is e.g. a long calculation that does not print anything, this shouldn't matter.

active = False; n = 0;
listenerFunction[] := Print["Listener pushed"];

Row@{Button["First", active = False; n = 100; 
   Do[Pause[.005]; n = n - 1, {i, 100}]; active = True;, 
   Method -> "Queued"], Spacer@5, Dynamic@n}

Dynamic[If[active, listenerFunction[]]; 
 Button[If[active, "active", "inactive"], active = ! active]]
István Zachar
  • 47,032
  • 20
  • 143
  • 291
  • That's an interesting approach, but I can't see it working for me. – Daroslav Oct 27 '12 at 10:35
  • @Daroslav Where does it fail? Perhaps set the Pause value to something smaller? Make sure that you evaluate it with a fresh kernel. – István Zachar Oct 27 '12 at 10:40
  • I'm sorry, I pressed enter too soon. Here's the rest of my comment:

    I want to use my button to run an animation with a dynamic Graphics object. Since it's long, the preemptive link times out. The good news is, I can split it into parts. So I need a Button, that will do a part of the job, and then calls itself (or a different Button) to do a part of the rest of the job, and so on.

    – Daroslav Oct 27 '12 at 10:42
  • @Daros You could put the "rest of the job" into listenerButtonFunction, and you can link an infinite number of buttons in this way. – István Zachar Oct 27 '12 at 11:13
  • I just thought I could, guess I needed some time to digest your idea ;) Thanks, that's really helpful, I'll try to adapt that. – Daroslav Oct 27 '12 at 11:31
  • Well, I tried to implement it, but as far as I understand what your code does is simply trigger the listenerButtonFunction with two different buttons: timer and dynamic. Timer button calls it and changes the appearance of the dynamic button, but it does not force that dynamic button to evaluate the function. – Daroslav Oct 27 '12 at 21:11
  • @Daroslav I've manufactured another way to set up a listener. Please check whether it fits your needs. – István Zachar Apr 03 '13 at 17:21