Message Boards Message Boards

Creating a dialog with a timed delay

Posted 12 years ago
I am trying to create a dialog with a timed delay: a user would not be able to interact with the dialog until a specified amount of time has passed.

Below is a series of examples that "almost" work.

This is my working prototype for constructng the behavior that I want:
count = 5;
button = Button[
  Dynamic[Refresh[If[count-- <= 0, "press me now", count],
    TrackedSymbols -> {}, UpdateInterval -> 1]], Print["foo"],
  Appearance -> Dynamic[If[count <= 0, "Palette", "None"]],
  Enabled -> Dynamic[count <= 0]]


This example works, but notice that the UpdateInterval is slower than specified. I don't understand why it is slow.
 signPost1[comment_] := DynamicModule[
   {
    thisNB = EvaluationNotebook[],
    button,
    count = 2
    },
   button =
    Button[Dynamic[
      Refresh[If[count-- <= 0, "press me", count],
      TrackedSymbols -> {}, UpdateInterval -> 1]],
    DialogReturn[NotebookWrite[thisNB, ToBoxes@TextCell["ok"]]],
    Appearance -> Dynamic@If[count <= 0, "Palette", "None"],
    Enabled -> Dynamic@(count <= 0)];
  DialogInput[Notebook[
    {Cell[comment, "Section"],
     Cell[BoxData[ToBoxes[Dynamic@button]], "Input"]}]];
  ]

signPost1["random comment"];


Here is another example in which I don't use dynamic for the timer, but use a RunScheduledTask. It is also slower than the argument to RunScheduledTask is specified:
 signPost2[comment_] := DynamicModule[
   {
    thisNB = EvaluationNotebook[],
    button,
    count = 2
    },
   RunScheduledTask[count--, {.5}];
   button =
    Button[Dynamic[
     Refresh[If[count-- <= 0, "press me", count],
      TrackedSymbols -> {}, UpdateInterval -> 1]],
    DialogReturn[NotebookWrite[thisNB, ToBoxes@TextCell["ok"]]],
    Appearance -> Dynamic@If[count <= 0, "Palette", "None"],
    Enabled -> Dynamic@(count <= 0)];
  DialogInput[Notebook[
    {Cell[comment, "Section"],
     Cell[BoxData[ToBoxes[Dynamic@button]], "Input"]}]];
  RemoveScheduledTask[ScheduledTasks[]];
  ]

signPost2["random comment"];

I am hoping someone might see why the timer in the dialog doesn't have the behavior that I am looking for, or can suggest a much cleaner way to do the same thing,
POSTED BY: W. Craig Carter
4 Replies
In answer to your questions:

* Yes, you should remove the ScheduledTask.  I knew you already knew to do that, and just didn't add it to my code to help make the other parts clear.  Plus, it really annoys me that ScheduledTasks aren't self-removing (I think something has been or will be done about that).
* The way you presented your problem and I presented my solution, it's not necessary to scope the TaggingRules to the cell because the TaggingRules are on the dialog box notebook.  So every time you create a new dialog box, you have a new instance of the TaggingRules "count" selector.  Perhaps your final problem looks different.
* As much as I'd like to help you out, I'm pretty swamped right now.  You can send your stuff, but I can't guarantee a response.
POSTED BY: John Fultz
Thanks Vitaliy,
I can imagine that the goal appears to be obscure. I'll expand on what that goal is, and how it relates to teaching with Mathematica,  below.  Perhaps the explanation of the goal should be in a new community discussion, as it is off-topic from this original question. 

Thanks John,
I'm stunned when my FrontEnd codes work as well!  I am embarrassed to admit how much time I put into making this work---more embarrassing is that it is several generations removed from one of your solutions to a related problem.  The fruits of too much inbreeding, and letting children (i.e, amature programmers like me) play with sharp objects.  I would never have thought of combining CurrentValue, Tagging, and RunScheduled task.  However, shouldn't the scheduled task be removed when finished?  Also, if I have many such dialogs, don't I need to restrict the scope of "count" to each cell? This scoping is what led me down the path to the DynamicModule.

 I'll adopt John's solution to put up signposts (think Burma shave).  I'll also need to adapt John's previous solution to this pause technique for material that contains evaluatable expressions.  John, if you have read this far and would be kind enough to help me out I would be very grateful---I'll send you the code I have for this so far.  I fear that my attempts to develop the vehicle to teach are preventing me from developing my materials science content as quickly as I would hope.
POSTED BY: W. Craig Carter
I like the idea of using a scheduled task, but your code has several problems with it. I'm frankly stunned that your code works at all. The issues:

* DynamicModule must display in order for it to function. Your DynamicModule displays no result.
* DialogInput freezes all kernel activity until it gets an answer. There is never any reason to use it unless the output of your Shift+Enter evaluation directly relies on an input from the user, and having it interact with Dynamic functionality is very, very dangerous.
* DynamicModule does not, by default, cross through notebooks. You need a DynamicModule wormhole to do that (although my solution does not do this because I contain the scope of the DynamicModule better).
* DynamicModule variables can't be accessed from scheduled tasks. Sorry, just a limitation of the system.
* You used a variant of RunScheduledTask which only runs the task once (by wrapping curly braces around the second argument).

Here's how I would do this:
 button[nb_] :=
   Button[Dynamic[
     With[{count = CurrentValue[EvaluationNotebook[], {TaggingRules, "count"}]},
       If[count <= 0, "press me", count]]],
     DialogReturn[NotebookWrite[nb, ToBoxes@TextCell["ok"]]],
     Enabled -> Dynamic[CurrentValue[EvaluationNotebook[], {TaggingRules, "count"}] <= 0]];
 
 signPost2[comment_] :=
   With[{nb = EvaluationNotebook[]},
    CreateDialog[Notebook[{Cell[comment, "Section"],
      Cell[BoxData[ToBoxes[
        DynamicModule[{}, button[nb],
          Initialization :> (With[{dialognb = EvaluationNotebook[]},
            RunScheduledTask[CurrentValue[dialognb, {TaggingRules, "count"}]--, 1]])
          ]]],
        "Input"]},
      TaggingRules -> {"count" -> 2}]
  ]]

Note that I use CreateDialog here so that the Shift+Enter evaluation returns immediately. I use TaggingRules on the dialog notebook in place of a DynamicModule variable (this is a well-documented meme...see the documentation for TaggingRules). I use With[] to pass EvaluationNotebook[] into RunScheduledTask[] because EvaluationNotebook[] would be undefined in a scheduled task. I use a DynamicModule in the dialog notebook to fire off an initialization, but it doesn't track any variables.
POSTED BY: John Fultz
I think it is a very interesting question. Maybe we could make use of Clock function? I am not sure what the final goal is, but this inspired me towards an actual Manipulate interface with controls that become active only after some delay time. You could use the same logic in your dialogs - if those dialogs will have any sorts of controls or interfaces. Not sure if this is helpful but here it is:
Manipulate[ Plot[Sin[x (1 + a x)], {x, 0, 6}], {a, 0, 2,   Enabled -> Dynamic@If[Clock[5, 5, 1] == 5, True, False, False]}]
POSTED BY: Vitaliy Kaurov
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract