close

Function Repository Resource:

DynamicEnabledButton

Source Notebook

Create a button that is automatically disabled when clicked and enabled when it finishes running its code

Contributed by: Richard Hennigan (Wolfram Research)

ResourceFunction["DynamicEnabledButton"][label,action]

represents a button that is labeled with label, evaluates action whenever it is clicked and automatically becomes disabled while action is evaluating.

ResourceFunction["DynamicEnabledButton"][Dynamic[x],label,action]

binds the enabled state to x.

Details and Options

ResourceFunction["DynamicEnabledButton"] is similar to Button but automatically sets up dynamic behavior for the Enabled option.
By default, ResourceFunction["DynamicEnabledButton"] starts enabled, becomes disabled when action starts evaluating and becomes enabled again as soon as action completes.
label can be any expression, including a dynamic one.
ResourceFunction["DynamicEnabledButton"] by default displays label in "Button" style, which typically uses the system button font.
ResourceFunction["DynamicEnabledButton"][label,action] maintains action in unevaluated form, evaluating it each time the button is clicked.
ResourceFunction["DynamicEnabledButton"] has the same options as Button, but the default value for Method is "Queued" instead of "Preemptive":
AlignmentAutomatichow to align contents within the button
AppearanceAutomaticthe overall appearance of the button
AutoActionFalsewhether to click the button automatically when the mouse is over it
BackgroundAutomaticbutton background color
BaselinePositionAutomaticalignment relative to surrounding text
BaseStyle"GenericButton"base style specifications for the button
ContentPaddingTruewhether to shrink the margins tightly around the contents
EnabledAutomaticwhether the button is enabled or grayed out
EvaluatorAutomaticthe kernel in which to evaluate expr
FrameMarginsAutomaticminimum margins to leave inside the frame
ImageMargins0margins around the image of the displayed button
ImageSizeFullthe overall image size of the displayed button
Method"Queued"the evaluation method to use
TooltipNonethe tooltip for the button
TooltipDelay0.`how long to delay before displaying the tooltip
TooltipStyle{}style specifications for the tooltip
Setting values for Enabled only controls the initial state. ResourceFunction["DynamicEnabledButton"] always becomes disabled when action starts evaluating and becomes enabled when action finishes evaluating.
In ResourceFunction["DynamicEnabledButton"][Dynamic[x],label,action], the value for x is automatically initialized to True or False, depending on the Enabled option.
With the default setting ImageSizeFull, a button will be sized to fill out its enclosing region in a Grid or related construct.
The setting ImageSizeAutomatic specifies that the button will be sized to fit its contents but will not expand to fill out an enclosing region.
Settings of Tiny, Small, Medium and Large for ImageSize specify buttons with certain system-standard minimum sizes.
Typical possible settings for the Appearance option include "DialogBox", "Frameless", "Palette" and "FramedPalette". In some cases, "AbuttingLeftRight", "AbuttingRight", etc. are also supported.
Appearance"Pressed" gives a button with a pressed appearance. Appearance{type,"Pressed"} gives a button of a certain type with a pressed appearance.
With AppearanceNone, label is displayed literally, without being placed in a button.
Typical possible settings for the Method option include "Preemptive" and "Queued".
ResourceFunction["DynamicEnabledButton"][prims,action] can be used within graphics objects to specify that action should be evaluated whenever the graphics primitives prims are clicked.
ResourceFunction["DynamicEnabledButton"][None,Dynamic[label],action,] can be used to specify a dynamic label and no dynamic binding without ambiguity.

Examples

Basic Examples (4) 

Create a button that automatically becomes disabled while it is running code:

In[1]:=
ResourceFunction["DynamicEnabledButton"]["test", Pause[5]]
Out[1]=
Image

Provide a symbol that is updated automatically as the button changes state:

In[2]:=
{ResourceFunction["DynamicEnabledButton"][Dynamic[x], "test", Pause[5]], Dynamic[x]}
Out[2]=
Image

Use a dynamic label:

In[3]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[z], Row[{"Button is enabled: ", Dynamic[z]}], Pause[5]]
Out[3]=
Image

Embed in other expressions:

In[4]:=
ResourceFunction["BirdSay"][
 ResourceFunction["DynamicEnabledButton"]["awesome", Pause[5]]]
Out[4]=
Image

Scope (9) 

Control the state of the button by setting values for the given symbol:

In[5]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[enabled], "test", Pause[5]]
Out[5]=
Image
In[6]:=
enabled = False
Out[6]=
Image

Use another control:

In[7]:=
Checkbox[Dynamic[enabled]]
Out[7]=
Image

Change the label depending on the state of the button:

In[8]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[doing],
 PaneSelector[{True -> "Do the thing", False -> ProgressIndicator[Appearance -> "Percolate"]}, Dynamic[doing]],
 Pause[5]
 ]
Out[8]=
Image

Create a group of buttons where only one can be clicked at a time:

In[9]:=
Column[{ResourceFunction["DynamicEnabledButton"][Dynamic[z], "first", Pause[5]], ResourceFunction["DynamicEnabledButton"][Dynamic[z], "second", Pause[5]]}]
Out[9]=
Image

Create multiple button groups:

In[10]:=
(* Evaluate this cell to get the example input *) CloudGet["https://www.wolframcloud.com/obj/8f5fd9d1-5891-4424-9d7d-db4bc56c6cf9"]
Out[10]=
Image

Use in a graphics expression:

In[11]:=
Graphics[{Dynamic[If[g, Red, Gray]], ResourceFunction["DynamicEnabledButton"][Dynamic[g], Disk[], Pause[5]]}]
Out[11]=
Image

Display the label literally, without the appearance of a button:

In[12]:=
ResourceFunction["DynamicEnabledButton"][
 Mouseover["click", Style["click", Italic]], Pause[5], Appearance -> None]
Out[12]=
Image

The state need not be bound to a symbol:

In[13]:=
states = <||>;
{
 ResourceFunction["DynamicEnabledButton"][Dynamic[states["first"]], "first", Pause[5]],
 ResourceFunction["DynamicEnabledButton"][Dynamic[states["second"]], "second", Pause[5]],
 Dynamic[states]
 }
Out[6]=
Image

Use the TaggingRules of the current notebook to store the button state:

In[14]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[CurrentValue[
   EvaluationNotebook[], {TaggingRules, "tag"}]], "test", Pause[5]]
Out[14]=
Image

Get the button state using CurrentValue:

In[15]:=
CurrentValue[EvaluationNotebook[], {TaggingRules, "tag"}]
Out[15]=
Image

Change the state:

In[16]:=
CurrentValue[EvaluationNotebook[], {TaggingRules, "tag"}] = False
Out[16]=
Image

To use a label of the form Dynamic[] without specifying the dynamic binding, None can be used as the first argument to avoid ambiguity:

In[17]:=
ResourceFunction["DynamicEnabledButton"][None, Dynamic[DateString[], UpdateInterval -> 1], Pause[5]]
Out[17]=
Image

Options (21) 

Alignment (1) 

Different predefined alignment options:

In[18]:=
Row[Table[
  ResourceFunction["DynamicEnabledButton"]["y", Pause[5], ImageSize -> {Automatic, 50}, Alignment -> a], {a, {Top, Center, Bottom}}], "xxx"]
Out[18]=
Image

Appearance (4) 

Predefined button appearances:

In[19]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Pause[5], Appearance -> a], {a, {"DialogBox", "Palette", "Frameless"}}]
Out[19]=
Image

On some platforms, the following appearances are also defined:

In[20]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Null, Appearance -> a], {a, {"AbuttingLeft", "AbuttingRight"}}]
Out[20]=
Image

Use a second element to get the appearance of a pressed button:

In[21]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Null, Appearance -> {a, "Pressed"}], {a, {"DialogBox", "Palette"}}]
Out[21]=
Image

Use a special appearance for the button:

In[22]:=
ResourceFunction["DynamicEnabledButton"]["xxx", Null, Appearance -> None]
Out[22]=
Image

AutoAction (2) 

By default, the button function does not evaluate until you click it:

In[23]:=
x = 0; {ResourceFunction["DynamicEnabledButton"]["xxx", x++], Dynamic[x]}
Out[23]=
Image

By setting AutoAction, the button function evaluates as you mouse over the button area:

In[24]:=
y = 0; {ResourceFunction["DynamicEnabledButton"]["yyy", y++, AutoAction -> True], Dynamic[y]}
Out[24]=
Image

Background (2) 

Change the background colors:

In[25]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Null, Background -> c], {c, {Pink, Green, Gray, Yellow}}]
Out[25]=
Image

Change the background color on every click:

In[26]:=
DynamicModule[{x = 0}, ResourceFunction["DynamicEnabledButton"]["xxx", x = Mod[x + 1/10, 1],
   Background -> Dynamic[Hue[x]]]]
Out[26]=
Image

BaselinePosition (2) 

Align with the surrounding text:

In[27]:=
Row[Table[
  ResourceFunction["DynamicEnabledButton"]["xxx", Null, BaselinePosition -> p], {p, {Top, Center, Bottom}}], "xxx"]
Out[27]=
Image

Change the baseline position on every button click:

In[28]:=
DynamicModule[{x = 1}, {"x", ResourceFunction["DynamicEnabledButton"]["xxx", x = Mod[x + 1, 3, 1], BaselinePosition -> Dynamic[Part[{Top, Center, Bottom}, x]]], "x"} // Row]
Out[28]=
Image

ContentPadding (1) 

Remove extra whitespace around a label with no ascenders or descenders:

In[29]:=
ResourceFunction["DynamicEnabledButton"][xxx, Null, FrameMargins -> 0,
  ContentPadding -> False]
Out[29]=
Image

Enabled (3) 

By default, DynamicEnabledButton is enabled:

In[30]:=
ResourceFunction["DynamicEnabledButton"]["aaa", Null]
Out[30]=
Image

By setting EnabledFalse, the button is disabled but visible in its current state:

In[31]:=
ResourceFunction["DynamicEnabledButton"]["aaa", Null, Enabled -> False]
Out[31]=
Image

By starting the button with EnabledFalse, the button can still be enabled manually by altering the given symbol:

In[32]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[aaa], "aaa", Null, Enabled -> False]
Out[32]=
Image
In[33]:=
Checkbox[Dynamic[aaa]]
Out[33]=
Image

FrameMargins (1) 

By setting FrameMargins, you make the button content area larger:

In[34]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Null, FrameMargins -> m], {m, {0, 5, 10, 20}}]
Out[34]=
Image

ImageMargins (1) 

By setting ImageMargins, you make the button area larger:

In[35]:=
Table[Framed@
  ResourceFunction["DynamicEnabledButton"]["xxx", Null, ImageMargins -> m], {m, {0, 5, 10, 20}}]
Out[35]=
Image

ImageSize (4) 

Use preset values:

In[36]:=
Table[ResourceFunction["DynamicEnabledButton"]["xxx", Null, ImageSize -> i], {i, {Tiny, Small, Medium, Large}}]
Out[36]=
Image

Or use any values:

In[37]:=
Column[Table[
  ResourceFunction["DynamicEnabledButton"]["xxx", Null, ImageSize -> i], {i, {50, 100, 150, 200}}]]
Out[37]=
Image

By setting the second element, you can also control the height:

In[38]:=
ResourceFunction["DynamicEnabledButton"]["xxx", Null, ImageSize -> {Automatic, 50}]
Out[38]=
Image

A fully customized image size:

In[39]:=
ResourceFunction["DynamicEnabledButton"]["xxx", Null, ImageSize -> {100, 50}]
Out[39]=
Image

Applications (2) 

Make a button that automatically indicates when it is busy computing something:

In[40]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[running],
 PaneSelector[{True -> "Run", False -> ProgressIndicator[Appearance -> "Percolate"]}, Dynamic[running]],
 Print[Table[Length[FactorInteger[2^n - 1]], {n, 50, 500, 50}]]
 ]
Out[40]=
Image
Image

Create a button that deletes itself after spending a few seconds to express how it feels about being deleted:

In[41]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[del],
 PaneSelector[{True -> "Delete", False -> Style["\[SadSmiley]", Large]}, Dynamic[del]],
 Pause[5];
 NotebookDelete[EvaluationCell[]]
 ]

Properties and Relations (2) 

Similar behavior to DynamicEnabledButton[Dynamic[x],label,action] can be achieved with Button:

In[42]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[aa], "test", Pause[5]]
Out[42]=
Image
In[43]:=
bb = True;
Button["test", bb = False; Pause[5]; bb = True, Enabled -> Dynamic[bb], Method -> "Queued"]
Out[32]=
Image

The enabled state of the button is restored even if an abort occurs:

In[44]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[cc], "test", Pause[1]; Abort[]; Pause[10]]
Out[44]=
Image

This prevents the button from ending up in a “bad” state:

In[45]:=
dd = True;
Button["test", dd = False; Pause[1]; Abort[]; Pause[10]; dd = True, Enabled -> Dynamic[dd], Method -> "Queued"]
Out[32]=
Image

Possible Issues (4) 

The appearance of the button will not update when using Method"Preemptive":

In[46]:=
ResourceFunction["DynamicEnabledButton"]["test", Pause[5], Method -> "Preemptive"]
Out[46]=
Image

In DynamicEnabledButton[Dynamic[x],label,action], the symbol x must not be a DynamicModule symbol in order for the enabled state to update:

In[47]:=
DynamicModule[{x}, ResourceFunction["DynamicEnabledButton"][Dynamic[x], "test", Pause[5]]]
Out[47]=
Image

This is also true for Button:

In[48]:=
DynamicModule[{x = True},
 Button["test", x = False; Pause[5]; x = True, Enabled -> Dynamic[x], Method -> "Queued"]
 ]
Out[48]=
Image

The dynamic binding must have just one argument and no options:

In[49]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[symbol, SingleEvaluation -> True], "label", Pause[5]]
Image
Out[49]=
Image

If the binding is unable to be set, no errors will be triggered when the button is created:

In[50]:=
protected = True;
Protect[protected]
Out[48]=
Image
In[51]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[protected], "label", Print["running"]; Pause[5]; Print["done"]]
Out[51]=
Image

Messages will appear when the button code executes and the state of the button will fail to update:

In[52]:=
ResourceFunction["DynamicEnabledButton"][Dynamic[protected], "label", Print["running"]; Pause[5]; Print["done"]]
Out[52]=
Image
Image
Image
Image
Image

Neat Examples (1) 

Watch Birdnardo do a flip:

In[53]:=
ResourceFunction["DynamicEnabledButton"][
 Dynamic[bs],
 PaneSelector[{
   True -> ResourceFunction["BirdSay"]["Click to watch me do a flip"],
   False -> ResourceFunction["BirdSay"]["Oh no! I'm stuck!", {Top, Right}]
   },
  Dynamic[bs]
  ],
 Pause[5]
 ]
Out[53]=
Image

Version History

  • 1.0.0 – 08 November 2019

Related Resources

License Information