I want to change the color of a button while it is pressed, pause for a short time and then change the color back to the original color.

I can't seem to figure out how to do this (tried various forms of DynamicModule and Dynamic, but no luck). This is what I tried so far:

  DynamicModule[{simulationFlag, bgnd = Automatic},
    simulationFlag = newSimulation;
    Dynamic[bgnd = Automatic; {simulationFlag}]],
  {{newSimulation, 0.02}, ControlType -> None},
    Button["New Simulation", Dynamic[newSimulation = newSimulation+1; {bgnd=Yellow}],
      Background -> Dynamic[bgnd]]}]
  • 4
    $\begingroup$ Could you please post whatever code you have tried so far? Also, do you want the button to revert after a short time while it is still pressed? $\endgroup$ – István Zachar Dec 2 '13 at 17:32
  • $\begingroup$ There are examples in the documentation: Button > Options > Background. $\endgroup$ – Silvia Dec 2 '13 at 19:47
  • $\begingroup$ If you rework the example in the docs and add a Pause you will get what you need. $\endgroup$ – Mike Honeychurch Dec 2 '13 at 21:32

For some unknown reason, @István's answer doesn't work here, so I rolled my own:

DynamicModule[{c = Yellow}, 
              Dynamic@Button["Press", Print["Pressed"]; 
                             c = Red; 
                             RunScheduledTask[c = Yellow; 
                                     RemoveScheduledTask[$ScheduledTask], {0}, AbsoluteTime[] + 3], 
                             Background -> c]]
  • $\begingroup$ I've corrected an error in my code (see comment below my post); could you please check whether it works on your end now? BTW, the problem with your approach is that multiple clicks start multiple tasks which stack up (check with Dynamic@Refresh[ScheduledTasks[], UpdateInterval->.1]). That's why I had to remove all tasks beforehand (not an elegant solution). $\endgroup$ – István Zachar Dec 2 '13 at 22:42
  • $\begingroup$ @IstvánZachar Your code still fails here. BTW, I see no problem with the tasks stacking up, as they are all removed after the delay from the last click has expired. $\endgroup$ – Dr. belisarius Dec 2 '13 at 22:46
  • $\begingroup$ Ok, I see now, we've implemented different things here. Your code reverts back n sec after the button is released, while mine reverts n sec after the button is pushed but not released. $\endgroup$ – István Zachar Dec 2 '13 at 22:56
  • $\begingroup$ @IstvánZachar Ha! I was testing your code with my understanding :) The failure was the test case $\endgroup$ – Dr. belisarius Dec 2 '13 at 23:00
  • 1
    $\begingroup$ @JackLaVigne Just type $ScheduledTask on your notebook and press F1 ... and get used to do that. Everybody does it all the time while working in Mathematica $\endgroup$ – Dr. belisarius Dec 2 '13 at 23:29

Explanation in detail what this code does:

  • Since the Button[..., Background -> color] has a rather ugly look, I use a Panel with colored background as the label of the button, this causes the button-in-a-button look.
  • When simply clicked (pressed and released immediately), nothing special happes, the button (and Panel) only changes appearance for the short time the button is pressed, then reverts back to normal.
  • However, when the button is pressed but not released, the behaviour is different: with the first registered event of "MouseDown", a timed task is started that evaluates delay seconds later and reverts the color of the Panel back to normal no matter whether the button is released or not, but still leaves the Button look pressed.
  • Releasing the button immediately removes any existing timed tasks.

So this code is a proof of principle that events can happen even while a button is in the iteraction phase. This might not be exactly what OP asked for but is my interpretation of the question.

delay = 2; (* time to stay blue when pressed *)
col = None; (* default color *)
down = False; (* default button state *)
     If[down, "Pushed", "Push!"], Background -> col, ImageMargins -> 5], 
     Appearance -> Dynamic@If[down, "Pressed", "Normal"]],
  "MouseDown" :> (
    down = True;
    RemoveScheduledTask /@ ScheduledTasks[]; (* to prevent multiple click-overlaps *)
    col = Hue[.6, 1, 1, .2]; 
    task = RunScheduledTask[col = None; RemoveScheduledTask@task, {delay}]),
  "MouseUp" :> (down = False; Quiet@RemoveScheduledTask@task; col = None)
  }, PassEventsDown -> True

Mathematica graphics

  • $\begingroup$ Strange ... doesn't work here (Mma 9 on winxp). It behaves as a normal button $\endgroup$ – Dr. belisarius Dec 2 '13 at 20:13
  • $\begingroup$ I don't know how to get a carriage return so the comment I make is going to run all together. Your solution works fine but is above my level. Here is what I tried but it doesn't work. Manipulate[ DynamicModule[{simulationFlag, bgnd = Automatic}, simulationFlag = newSimulation; Pause[0.5]; Dynamic[ bgnd = Automatic; {simulationFlag} ] ] , {{newSimulation, 0.02}, ControlType -> None}, Row[{ Button[ "New Simulation", Dynamic[newSimulation = newSimulation + 1; {bgnd = Yellow}], Background -> Dynamic[bgnd] ] }] ] $\endgroup$ – Jack LaVigne Dec 2 '13 at 20:59
  • $\begingroup$ @István I cannot understand why, when the scheduled task is executed, the button also gets raised (no more pressed). I do not find anything doing that in your code. Is it possible to keep it pressed? (MMA v9) $\endgroup$ – user8074 Dec 2 '13 at 21:11
  • $\begingroup$ @user8074 Thanks for pointing it out! Actually, if you check the previous version, you can see that I made a mistake and accidentally merged Button option Appearance into the Panel. Strangely enough, it worked, so I missed it. This new version should behave as expected. $\endgroup$ – István Zachar Dec 2 '13 at 22:37
  • $\begingroup$ @István now what I see is quite unusual: two buttons one over the other. When I click them, both get pressed. Then, after 2 second, the inner button lifts up, while the outer button remains pressed. After releasing, both buttons get up. It may be that the color change event cancels the button-pressed event for some reason. Do you see the same? $\endgroup$ – user8074 Dec 4 '13 at 2:07

Here are a couple of ways. One uses UpdateInterval. The second uses Clock. The Clock method continually uses some CPU to update the front end all the while the alternate color (Yellow) is displayed. The first method makes only one update. In this way it is more efficient.

In both cases, when the button is pressed, the background color is replaced by a dynamic object that updates itself and persists only while the alternate color is displayed. The dynamic object is then destroyed after the interval has elasped and the color is replaced with the default color (Red, by my choice).

UpdateInterval method:

DynamicModule[{bgnd = Red, timer = Null, switch},
  bgnd = Yellow;
  switch = 0;
  timer = Hold @ Refresh[If[switch < 1, switch++, timer = Null; bgnd = Red], 
     UpdateInterval -> 2, TrackedSymbols :> {}],
  Background -> Dynamic[ReleaseHold @ timer; bgnd]

Clock method:

DynamicModule[{bgnd = Red, clicktime = 0, duration = 2},
   clicktime = Clock[Infinity]; 
   bgnd = Hold @ If[Clock[Infinity] < clicktime + duration, Green, bgnd = Red],
   Background -> Dynamic[ReleaseHold @ bgnd]

With respect to the code added in an edit, which seems possibly to be seeking a different sort of behavior -- that is, not for a certain amount of time, but while the Manipulate updates -- here is a simplified version that works:

 bgnd = Automatic;
 {{newSimulation, 0.02}, ControlType -> None},
 {{bgnd, Automatic}, ControlType -> None}, 
 Button["New Simulation", newSimulation = newSimulation + 1; 
  bgnd = Yellow, Background -> Dynamic[bgnd]]]

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.