9
$\begingroup$

I want to ask the user (me) to make a binary choice, but also to give myself only 5 seconds in which to respond. In the absence of a response within 5 seconds, I want my code to close the dialog box and to make a default choice. The following works in all respects, except that the time allowed never seems to expire. What am I doing wrong ? Also, is the While loop thrashing the system by repeatedly making new dialog boxes ? They don't proliferate - there is only one. Nor does the display seem to flicker.

response = Null;
starttime = AbsoluteTime[];
While[And[response == Null, AbsoluteTime[] - starttime < 5],
  response =
   ChoiceDialog["potato", {Continue -> a, Quit -> b},
    WindowTitle -> "Melon"]
  ];
DialogReturn[];
Print[response]

EDIT: UPDATE:

Following Sjoerd's fantastic help, I have written the following:

  timeoutuserinput[message_, delaytime_] := Module[{localvars},
  starttime = AbsoluteTime[];
  DialogInput[
   {
    message,
    Dynamic[
     If[AbsoluteTime[] - starttime > delaytime, 
      DialogReturn[response = "continue"];], UpdateInterval -> 1],
    ChoiceButtons[{"Continue", 
      "Quit"}, {DialogReturn[response = "continue"], 
      DialogReturn[response = "quit"]}, Spacings -> 10]},
   WindowTitle -> "H E L L O  !"
   ];
  response
  ]

which I am invoking like so:

timeoutuserinput["cacti are good today", 10]

Being very demanding, I would like to know whether it's possible to prevent the word "Null" from appearing, underneath where "cacti are good today" appears in the dialog box.

$\endgroup$
8
$\begingroup$

I'm honestly not entirely satisfied with this answer, but it should get you on the right track:

    dialogWithTimeLimit[Dynamic[val_Symbol], limit_?NumericQ] := With[{
       startTime = AbsoluteTime[]
       },
      CreateDialog[
        {
         Dynamic[
          If[AbsoluteTime[] - startTime > limit, 
           DialogReturn[val = "time's up"]];
          StringForm["You have `1` seconds", 
           Ceiling[limit + startTime - AbsoluteTime[]]],
          UpdateInterval -> 0.1
          ],
         Button["Choice 1", DialogReturn[val = 1]],
         Button["Cancel", DialogReturn[val = $Canceled]]
         }
        ];
      ];

You can call it with:

dialogWithTimeLimit[Dynamic[returnValue], 5]

This creates a pop-up with time limit 5 that stores the outcome inside of the variable returnValue. It works quite well, but it doesn't halt standard evaluation like DialogInput and ChoiceDialog do, which is a bit inconvenient. You can see this when you evaluate something like:

dialogWithTimeLimit[Dynamic[returnValue], 10];
Print["Hi"]

The Print will execute immediately, rather than after the dialog finishes. However, I couldn't get this method to work reliably with DialogInput or ChoiceDialog because they don't seem to respect the UpdateInterval option of the Dynamic for some reason.

edit

Ok, let's do a short Q&A then to answer the updated question. The reason the dialog timeoutuserinput shows Null is simply because that's the evaluation result from the first argument of the Dynamic. It's a good rule of thumb to keep in mind that Dynamics in Mathematica are always expressions that are shown on screen or linked to controllers. The answer here is to simply turn the dynamic into something we want to see:

timeoutuserinput[message_, delaytime_] := Module[{localvars},
  starttime = AbsoluteTime[];
  DialogInput[
   {
    Dynamic[
     If[AbsoluteTime[] - starttime > delaytime, 
      DialogReturn[response = "continue"]
     ];
     message,
     UpdateInterval -> 1
    ],
    ChoiceButtons[{"Continue", 
      "Quit"}, {DialogReturn[response = "continue"], 
      DialogReturn[response = "quit"]}, Spacings -> 10]},
   WindowTitle -> "H E L L O  !"
   ]
];

The idea here is that every time the Dynamic needs updating, it will evaluate its first argument. It will first evaluate the If statement to check the time. If it gets past that, it will return the message and display it. So in a sense, the message is now an active element on the window that keeps track of the time.

$\endgroup$
  • $\begingroup$ Thank you @Sjoerd Smit, that's very nice ! I must admit that the not halting is a problem for me, because my intended application is that I have a very large computation, the results of which I want to save to disk periodically, (in case of power cuts etc), each time giving the user to option to quit gracefully or to continue, and if he (me) doesn't make a choice within say 30 secs, defaulting to continuing the computation. $\endgroup$ – Simon Sep 10 '18 at 16:02
  • 1
    $\begingroup$ You can replace CreateDialog with DialogInput to halt the evaluation. It will work roughly right, but the timer will not update very often so the time out might not be exactly 30 seconds. You'd have to try it to see if it's good enough for you. I just tried it, and it seems like the dialog checks the time limit every ~10 seconds, so it should still be somewhat functional. $\endgroup$ – Sjoerd Smit Sep 10 '18 at 17:24
  • $\begingroup$ Thank you very much ! That works as you said it would. I am asking a lot here, considering that Mathematica isn't supposed to be an all-singing all-dancing low level programming language, but I don't imagine you'd know whether it's possible to suppress that "Null" message that seems to be generated by the Dynamic command ? $\endgroup$ – Simon Sep 10 '18 at 21:45
  • 1
    $\begingroup$ What do you mean by that exactly? Null is simply the default symbol Mathematica uses to signify that an evaluation returns no value. The result of the dialog is captured in the returnValue symbol you give as the first argument. Where are you seeing Null appear? $\endgroup$ – Sjoerd Smit Sep 11 '18 at 8:18
  • $\begingroup$ Dear @Sjoerd Smit, thank you for responding again ! I have edited the original question to explain what I mean. Apologies if this is not correct stackexchange protocol, however. $\endgroup$ – Simon Sep 11 '18 at 13:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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