2

Consider this (edit: Pause[3] represents some long computation the button should do):

Manipulate[Dynamic@output, Button["do", 
    output = "Paused..."; FinishDynamic[]; Pause[3]; output = "done"]]

This works in that we see the Paused message briefly. But it uses a global variable output.

1) If you take out the FinishDynamic[], or the first Dynamic@ it does not work.

2) If you add a {output,ControlType->None} to the Manipulate, it does not work.

3) Similarly for wrapping it all within a DynamicModule[{output},]

Is there a better way to update the output of a Manipulate from within a Button? I'd like to avoid eg Refresh every second since the recalculation will in principle happen very rarely.

Philip Maymin
  • 1,163
  • 8
  • 12

2 Answers2

3

I don't think that anything is wrong with Michaels answer but I wanted to mention that the following does what I think you expect in a somewhat more straightforward way:

Manipulate[
 Dynamic[output, TrackedSymbols :> {output}],
  Button["do", output = "Paused..."; FinishDynamic[]; Pause[3]; 
   output = "done",
   Method -> "Queued"
 ],
 {output, ControlType -> None}
]

the trick is to add the TrackedSymbols option to Dynamic. I did additionally add the Method->"Queued" option to the button, which is not necessary for this example to run but certainly is a good idea once your calculation (or Pause) takes or could take more than 6 second (or more precisely what DynamicEvaluationTimeout is set to).

I would also like to mention that I think once you start to build an interface where you want precise control about when which part of the code is evaluated it might actually become simpler/more straightforward to use the lower level "dynamic language" constructs directly instead of manipulating Manipulate, e.g.:

DynamicModule[{output = ""},
  Panel[
    Column[{
      Button["Do",
        output = "Paused...";
        Pause[3];
        output = "Done.";
        ,
        Method -> "Queued"
      ],
      Panel[Pane[Dynamic[output, TrackedSymbols :> {output}], {100, 50}]]
    }]
  ]
]
Albert Retey
  • 23,585
  • 60
  • 104
  • Both your and Michael's solutions are perfect. I particularly like how this one requires fewer edits to the example code, and the self-TrackedSymbols trick is an interesting one to know for the future. Thanks! – Philip Maymin Feb 20 '15 at 15:43
  • @PhilipMaymin: thanks for the accept. I would like to draw your attention to the Method->"Queued" setting, you almost certainly will find that necessary for your real problem... – Albert Retey Feb 20 '15 at 16:02
  • Yes, I use that of course, thank you. Just left it out of the question for brevity, probably too much brevity. :) Thanks again. – Philip Maymin Feb 20 '15 at 20:46
1

I'm not entirely sure what you're after. Here are two ideas. The first one preserves the waiting 3 seconds. If that's not important, see further down.

Manipulate[output,
 {{output, "new", ""},
  DynamicModule[{timer = Infinity},
    Button[
     DynamicWrapper["do", 
      If[Clock[{0, Infinity}] >= timer + 3, output = "done"]],
     output = "Paused..."; timer = Clock[{0, Infinity}]]] &},
 TrackedSymbols :> {output}]

I used something like {{update, 0}, Button["Update", update++] &} in this answer. If trial appears in the body of the Manipulate, even just as update;. Here's an example:

Manipulate[update;
 RandomReal[],
 {{update, 0}, None},
 Button["Update", update++]
 ]

Update - Third example: I'm still not sure how Pause[3] and output are to be integrated into the Manipulate. Here's another idea:

Manipulate[
 If[output === "Paused",
  output = (Pause[3]; "done")];
 Dynamic@output,
 {{output, "done"}, None},
 Button["do", output = "Paused"]]
Michael E2
  • 235,386
  • 17
  • 334
  • 747
  • I'm trying to understand your first one. The Pause was just to represent some long computation. Where would I put the bulk of such code in your example? – Philip Maymin Feb 20 '15 at 03:10
  • Also, I like the Button& approach, but when I try Manipulate[Dynamic@output, {{output, "start",}, Button["do", output = "Paused..."; FinishDynamic[]; Pause[3]; output = "done"] &}] it never displays "Paused" – Philip Maymin Feb 20 '15 at 03:10
  • I don't know DynamicWrapper very well but it seems to essentially refresh every second? For example running counter = 0; Button[DynamicWrapper["hi", counter++], Print@counter] and pressing the button gives large numbers. – Philip Maymin Feb 20 '15 at 03:14
  • @PhilipMaymin I think the first solution above is not what you're after, if Pause represents any function. -- The Button (2nd comment) never displays "Paused" because the whole computation is completed before the Front End is notified of any updates. -- The counter++ is executed every time counter changes value, similar to Dynamic[counter++]; and since it changes value every time counter++ is executed, you get an infinite loop. – Michael E2 Feb 20 '15 at 03:27
  • Your updated solution is perfect! Great solution. Thanks very much. – Philip Maymin Feb 20 '15 at 03:42
  • @PhilipMaymin You're welcome. – Michael E2 Feb 20 '15 at 03:43