After the execution, I want that with one click on the square, I can see the square shrink to a rectangle of size (4,2) for two seconds, and then shrinks again to a rectangle of size (4,1), as indicated in the function f[].For the moment, the action of clicking on the square does trigger these events, but I can only see the final result after the two seconds have passed.
I believe you only see the final result after f[] has fully evaluated because the “MouseClicked” event is using preemptive evaluation, which basically disallows the interrupting dynamic update you were expecting when y = 2 is evaluated.
You can use the Method option on some objects to set their evaluation type. The choice is generally (and I think always, to the best of my knowledge) either “Preemptive” or “Queued”. There are a few details about these evaluation methods at ref/Button:
With the default setting Method → “Preemptive”, button actions are performed immediately, preempting any other evaluation, but are allocated only a limited time to complete.
With the setting Method → “Queued”, button actions are added to the current queue of evaluations, and are performed when other evaluations are complete. No time limit is applied.
With “Queued”, an update of y during the action evaluation would trigger an update of visible dynamic objects depending on y. With “Preemptive”, the action evaluation finishes before dynamic updates can occur.
For a quick demo, evaluate these three inputs and try the buttons. Watch the value of y shown by the Dynamic:
Dynamic@y
y = 1; Button["testing preemptive", y = 2; Pause@2; y = 3]
y = 1; Button["testing queued", y = 2; Pause@2; y = 3,
Method -> "Queued"]
I don’t know if there is a way to force the “MouseClicked” event callback to use non-preemptive evaluation (if my guess about the cause of this behavior is in fact correct).
You can use Clock inside Dynamic to make the value represented by y depend on the time. It will auto-update inside the rectangle while the `Clock` is present. Once a certain amount of time has elapsed, the code for y resets y to the constant value 1, which removes the dynamic Clock. Dynamic updating stops until the next mouse click instantiates another Clock.
DynamicModule[{pt = {0, 0}, t0, t1, y = 1},
Magnify[
ClickPane[
Graphics[{
Rectangle[{0, 0}, {Dynamic[y], 1}],
Red, PointSize[Large], Dynamic@Point[pt]},
PlotRange -> {{0, 4}, {0, 2}}, Frame -> True,
FrameLabel -> Dynamic[{t0, t1}]],
(
pt = #;
y = ( (* set y to dynamic clock *)
t0 = Null; (* flags start of clock *)
Dynamic[
t1 = Clock[Infinity]; (* Clock inside Dynamic triggers continual updating *)
If[! NumericQ[t0], t0 = t1]; (* initialize t0 first time through *)
If[t1 - t0 > 4, (* stopping criterion *)
y = 1, (* reset y to constant 1 *)
If[t1 - t0 > 2, 4, 2]] (* dynamic value of y while Clock is running *)
]
)
) &], 0.5]]
Thank you so much Mr Rummler for providing exactly the function that is needed here. I thought for a while it was impossible to evaluate events dynamically within a EventHandler action/function, but FinishDynamic[] did exactly what I wanted.
Thank you also Mr Rogers for letting us know more about the Clock option and its use.