Abstract
My task sounds simple and straight forward but not all is as it first appears. I just need a Button
that waits to be Clicked
before displaying a countdown
timer in the label. Button
will eventually do a lot more which I have coded before including evaluation control however everything I tried to stall countdown
just doesn't work. The Clock
in countdown
always starts when the Button
is created even if the current value of label isn't displayed as demonstrated in Button
samples given below.
I even tried wrapping and embedding Button
with multiple layers of mouse EventHandlers
which worked with styles like Background
but failed completely on countdown
(did not update label). I'm almost positive I did something wrong. Unfortunately that code was lost. Please help me find a solution. I have been trying to solve this off and on for months.
countdown
(Clock)
Here is my latest iteration of countdown
. As you can see it's wrapped in an anonymous Function
which has attributes HoldAll
(should not Evaluate
until all arguments are provided) in an attempt to force the Clock
in countdown
to wait on a mouse event. A few of the various Buttons
attempted are shown afterwards.
countdown =
Function[{s, n}, Dynamic[s - Clock[{0, s, 1}, s, n]]];
(* demo countdown timer *)
Row[{"almost bare naked countdown \[Rule] ", countdown[10, 1]}]
Button 0: Global
This is the only Button
not wrapped in a DynamicModule
and in which label x
is set to an intermediary variable named timer
(this variable is only used here) so that Clock
in countdown
can be observed to start without a Click
event (Evaluate Cells
may need to be executed more than once). Immediate Evaluation
(before mouse event) is not how a Button
is supposed to behave.
Quiet@ClearAll[x];
Row[{"Global label (x) set to intermediate variable (timer) \[Rule] ",
Button[Dynamic[x = timer], (timer := countdown[60, 1]) &,
ImageSize -> {75, 30}]}]
Button 1: Click
After momentary wait click Button
. If less than 60 Clock
in countdown
did not wait for Click
event. Also note that Clock
continued to run dynamically despite not displaying updated value in label x
before Click
event. This even continues to run if Cell
containing Button
is scrolled out of view. This is not how Dynamic
is supposed to work. Although AutoAction -> False
is the default setting it is explicitly set for reasons which will become clear in Button 2: (Hover).
DynamicModule[{x},
Row[{"DynamicModule Button with regular Click \[Rule] ",
Button[Dynamic[x, (#) &,
Initialization :> (x = "wait 5s then Click")], (x :=
countdown[60, 1]) &, ImageSize -> {150, 30},
AutoAction -> False]}]]
Button 2: Hover
After momentary wait hover Button
. If less than 60 Clock
in countdown
did not wait for Hover
event. Again note that this Button 2 (Hover) exhibits all the same dynamics as Button 1 (Click). That is because AutoAction
does not supercharge Evaluation
. The only thing it does is emulate a Click
event with Hover
.
DynamicModule[{x},
Row[{"DynamicModule Button with Hover \[Rule] ",
Button[Dynamic[x, (#) &,
Initialization :> (x = "wait 5s then Hover")], (x :=
countdown[60, 1]) &, ImageSize -> {150, 30},
AutoAction -> True]}]]
Why Stress Click vs. Hover?
I stress the role of option AutoAction
because I posted similar questions before at mathematica.stackexchange.com...
- https://mathematica.stackexchange.com/questions/253172/please-help-with-dynamic-autosave-button-that-only-halfway-works
- https://mathematica.stackexchange.com/questions/253544/my-dynamic-button-evaluates-as-soon-as-its-created-how-do-i-stop-this-behavior
but the few well-meaning good folks who tried to help only provided halfway good but mostly unsatisfactory answers. They were under the mistaken impression that AutoAction
would control Clock
evaluation or that there was nothing wrong with my code. I believe they didn't wait long enough after Button
was rendered to observe the immediate invocation of countdown
without a mouse event. It was mostly my bad for not properly setting up demos. That is what I tried to avoid here.
Closing Thoughts
The official Wolfram Documentation isn't very clear on how Clock
evaluation is supposed to work. I don't believe there is anything wrong with Clock
but it could have been designed with better evaluation control. However it is absolute on how Dynamic
and Button
are designed to work. Dynamic
objects should never update when not in view (unless contained in DynamicWrapper
) and Button
should never permit evaluation of expression unless invoked by a mouse or similar event. I believe these are bugs with both and Button
and Dynamic
. However I still have faith that there is a simple work-around (without injecting code with spaghettis-like low-level procedural loops and routines) using some of the deeper Evaluation
controls provided by Mathematica.