5
$\begingroup$

I have not been able to find the answer for the following problem, and would be happy to be educated.

I am writing a custom user interface around some code that has lengthy calculations. In the standard notebook, I can use PrintTemporary to show the status of the internal variable during the calculation. Now I would like that the print messages are directed into some Panel inside a DynamicModule. The calculation might be triggered by pressing a Button for example.

The best I have achieved so far is that after pressing the button, nothing happens, and at the end of the calculation, all values are spit out at once, and the last one appears in the Panel. This happens with SessionSubmit[ScheduledTask[...]].

What I did is define a global variable (message), which is updated during the long calculation, and in the ScheduledTask a local message is assigned to the Global`message. The local message is displayed in the Panel. I can also print the local message variable, and in this way I see that indeed it got inbetween all values, but only at the end of the function call, these are printed / displayed in the Panel.

How can I achieve that the Panel constantly (or every second) updates during the calculation?

The minimal code example would be:

(****************************)

Global`globalMessage = "2";

externalFunc[] := Block[{},
 Global`globalMessage = "3";
 Pause[4];
 Global`globalMessage = "4";
 Pause[4];
 Global`globalMessage = "5";
];

insertBelowEvaluationCell[expr_, nb_] := 
 (SelectionMove[nb, After, EvaluationCell];
 NotebookWrite[nb, Cell[BoxData@ToBoxes[expr], "Print"]]);
nb = EvaluationNotebook[];

diag = CreateDialog[DynamicModule[{testFunc, message, task},
Dynamic@
 Column[{Button["Test", testFunc[]], 
   Panel[Dynamic[message], "Message"], 
   Button["Close", TaskRemove[task]; DialogReturn[]]}], 
Initialization :> (message = "1"; 
  testFunc[] := Block[{}, externalFunc[]];
  task = 
   SessionSubmit[
    ScheduledTask[message = Global`globalMessage; 
     Global`insertBelowEvaluationCell[message, Global`nb], 1]];
  )]];

(*******************)

Thanks a lot for your help!

$\endgroup$
3
  • $\begingroup$ Can you provide a minimal example of the code to reproduce the problem? You can use Pause instead of real calculations. $\endgroup$
    – Kuba
    Commented Jan 16, 2019 at 19:07
  • $\begingroup$ You may have to assign the message to a dynamic variable and use FinishDynamic to ensure updating at each desired step. But we need more information. $\endgroup$ Commented Jan 17, 2019 at 2:02
  • $\begingroup$ I have now added a minimal code example, showing my attempt so far. Thanks! $\endgroup$ Commented Jan 17, 2019 at 6:51

1 Answer 1

3
$\begingroup$

There are two problems but only one is your fault :)

  1. To make Dynamic @ message responsive to changes from a scheduled task:

    you need to workaround this bug: What is the difference between Dynamic[x] and Dynamic[ h[x] ] for DynamicModule variables?

    Solution: use Dynamic[message+0] or something equally ridiculous. Not your fault.


  1. If you want intermediate results from testFunc/externalFunc be dynamically monitored you need to run it on the MainLink (Method->"Queued"), otherwise the FrontEnd is just waiting for testFunc to finish and will not react.

    Solution: Button["Test", testFunc[], Method -> "Queued"]:

    See tutorial / AdvancedDynamicFunctionality for more about that.


Closely related: Working with DynamicModule: Tracking the progress of Initialization

Related: Working with DynamicModule: ScheduledTasks with local variables

$\endgroup$
2
  • $\begingroup$ Thank you very much! That solves the issue! $\endgroup$ Commented Jan 17, 2019 at 10:03
  • 1
    $\begingroup$ @StefanGillessen great, take the tour then :-) $\endgroup$
    – Kuba
    Commented Jan 17, 2019 at 10:14

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