Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I have a Dynamic-based GUI, and one part of it will kick off a calculation that could take longer than the default 5-second dynamic timeout.

I know that Button has a Method -> "Queued" option for performing an evaluation on the main link rather than by doing a pre-emptive evaluation.

How can I initiate a main link evaluation without requiring the user to click a button?

share|improve this question

4 Answers 4

up vote 18 down vote accepted

If you pass SynchronousUpdating->False to Dynamic, it will perform operations on the main link. Note that this only works where Dynamic is displayed as a typeset result (i.e., typeset as a DynamicBox). It does not presently work where Dynamic is used to give a value to a control (such as Slider) or an option.

A quick survey of other constructs...

ActionMenu has a Method option which works identically to Button.

EventHandler, as of version 9, has no way to do main link evaluations.

FrontEndDynamicExpression and friends, as of version 9, have no way to do main link evaluations.

share|improve this answer

While John Fultz gave a depressing answer concerning GUI controls, I doubted that this cannot be done in Mathematica. A bit of exploration and Rojo's extremely useful answer helped me to come up with a workaround to simulate Method -> Queued for GUI controllers other than Button.

The function queued accepts any dynamic controller as its first argument and any command as its second argument and whenever dynamic manipulation of the controller is done, it fires the command just like Button[..., Method -> "Queued"] would do:

Attributes[queued] = {HoldRest};
queued[gui_, action_] := DynamicModule[{trigger = False},
   DynamicWrapper[EventHandler[gui,
     {"MouseDown" :> (trigger = False), 
      "MouseDragged" :> (trigger = False), 
      "MouseUp" :> (trigger = True)},
     PassEventsDown -> True, PassEventsUp -> False],
    If[trigger, Refresh[action, None]], SynchronousUpdating -> False
    ]];

Now simulate a long calculation that depends on a slider-value and wrap the whole in queued. Whenever the Slider is released, the updating of the long calculation starts:

long[x_] := Module[{a = .3}, Do[a = x a (1 - a), {i, 10^6}]];
active = False; x = 3.5;
queued[Slider[Dynamic[x], {1, 4}, Appearance -> "Labeled"], 
   active = True; long@x; active = False;]
Dynamic@If[active, ProgressIndicator[i, {0, 10^6}], "Ready."]

enter image description here

Just for reference, the same cannot be done with the second argument of Dynamic (as discussed here). This won't work:

Slider@Dynamic[x, {(x = #) &, active = True; long@x; active = False;}]

Update

Concerning ContinuousAction -> False, my problem is twofold: first, it does not update the controller variable continuously (which is an unnecessary limitation in my case), second, the following code won't work as expected:

trigger = False; x = 3.5;
Slider[Dynamic[x, (x = #; trigger = True; long[x]; trigger = False;) &], {1, 4}, 
 ContinuousAction -> False, Appearance -> "Labeled"]
Dynamic@If[trigger, ProgressIndicator[i, {0, 10^6}], "Ready."]

Neither does this:

trigger = False; x = 3.5;
DynamicWrapper[Slider[Dynamic[x, (x = #; trigger = True;) &], {1, 4}, 
  ContinuousAction -> False, Appearance -> "Labeled"], 
 If[trigger, Refresh[long[x]; trigger = False;, None]]]
Dynamic@If[trigger, ProgressIndicator[i, {0, 10^6}], "Ready."]
share|improve this answer
    
I think that there is a somewhat simpler way to achieve the same: You can use as the first argument to the DynamicWrapper something like the following: Slider[Dynamic[x, (x = #; trigger = True) &], {1, 4}, ContinuousAction -> False, Appearance -> "Labeled"]. This is not only somewhat simpler, it also will work with gui elements which are not triggered by the mouse, as e.g. InputField... –  Albert Retey Mar 30 '13 at 20:42
    
@Albert Please see edit about my problems with your proposed solution. Concerning those gui elements that are not mouse-driven, one can easily modify the underlying EventHandler to handle those. –  István Zachar Mar 31 '13 at 9:46
    
I now see that it was not enough to just post that fragment to get the correct behavior. I think the complete solution does work as you want, but I needed to add some to make the controller variable change continuously. As this is now too long for just a comment I added an extra answer... –  Albert Retey Apr 2 '13 at 10:12

Based on Istvans solution this should do the same thing, but is somewhat simpler in that it avoids the EventHandler which would need adoption to match the possible interactions of the gui element used. The use of the three "change functions" also makes possible to continuously update the controller variable but only trigger the long calculation when the "editing" is finished:

long[x_] := Module[{a = .3}, Do[a = x a (1 - a), {i, 10^6}]]
x = 3.5; active = False;
DynamicModule[{trigger = False},
 Column[{
   DynamicWrapper[
    Slider[
     Dynamic[x, {(x = #) &, (x = #) &, (x = #; trigger = True) &}],
     {1, 4}, ContinuousAction -> True, Appearance -> "Labeled"
     ],
    If[trigger, 
     Refresh[active = True; long@x; active = False; trigger = False;, 
      None]],
    SynchronousUpdating -> False
    ],
   Dynamic@If[active, ProgressIndicator[i, {0, 10^6}], "Ready."]
   }]
 ]

This should work just as well for e.g. an InputField:

long[x_] := Module[{a = .3}, Do[a = x a (1 - a), {i, 10^6}]]
x = 3.5; active = False;
DynamicModule[{trigger = False},
 Column[{
   DynamicWrapper[
    InputField[
     Dynamic[x, {(x = #) &, (x = #) &, (x = #; trigger = True) &}],
     Number, ContinuousAction -> False
     ],
    If[trigger, 
     Refresh[active = True; long@x; active = False; trigger = False;, 
      None]],
    SynchronousUpdating -> False
    ],
   Dynamic@If[active, ProgressIndicator[i, {0, 10^6}], "Ready."]
   }]
 ]
share|improve this answer
    
+1 Marvellous! This should be part of Mathematica 10, in the form of Slider[..., Method -> "Queued"] and similar for all gui controls. I was about to aim for solving {$f_{start}$, $f$, $f_{end}$}, but this is now handled beautifully. –  István Zachar Apr 2 '13 at 12:41

You can also do this inside a Manipulate. Two useful settings are:

SynchronousUpdating -> False

and

ContinuousAction -> False

which apply to any of the possible control types (including sliders). The first specifies "whether or not contents are evaluated synchronously" and the second specifies whether an "action should be taken continuously while controls are moved". The latter is something like Istvan's queued slider.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.