Creating Dialog Boxes

In the Wolfram System, dialog boxes are customized notebooks used to provide users with information and/or request user input.

There are two properties associated with dialogs.

Dialog properties.

A modal dialog forces the user to respond to the dialog before doing anything else. This allows the front end to acquire the information necessary to either complete or initiate an evaluation. For example, when most applications close, a modal dialog will appear, prompting the user to save changes. Since the response is crucial in determining how the application should close, the dialog will prevent access to the other parts of the program until the user has responded to it. Setting the option (RefLink[Modal, paclet:ref/Modal])->(RefLink[True, paclet:ref/True]) will make a dialog modal.

A blocking dialog halts a running evaluation until the user responds to it, but does not prevent access to other parts of the front end. The kernel in which these dialogs are evaluated will effectively block until the dialog is closed. For example, a choice dialog will start an evaluation, wait until the user chooses a value, and then complete the evaluation by returning the value. Any other evaluations that are sent through the main link while the dialog is open will be queued and evaluated once the dialog is closed.

Some dialogs are neither modal nor blocking, such as the system find dialog and message dialogs.

Dialog Buttons

Dialogs typically include buttons to allow users to respond to a question, a message, or other requested input. One of these buttons is the default action and is highlighted when the dialog opens. Another button that is almost always present is the cancel button, which will close the dialog and abort the dialog's action.

In the Wolfram System, the default and cancel buttons can be created using a series of streamlined functions.

Dialog buttons.

In dialogs created using (RefLink[DialogInput, paclet:ref/DialogInput]) or (RefLink[CreateDialog, paclet:ref/CreateDialog]), pressing MacOSXReturnEnter is equivalent to clicking the OK (default) button and pressing Esc is equivalent to clicking the Cancel button. If there are several default buttons in a single dialog, MacOSXReturnEnter will use the first one in the dialog. Similarly, pressing Esc will use the first Cancel button in the dialog.

Create a cancel button and a default button in a row.

Row[{CancelButton[],DefaultButton[]}]

(RefLink[ChoiceButtons, paclet:ref/ChoiceButtons]) will display the default and cancel buttons in the standard order for the current computer system.

ChoiceButtons[]

Dialog Notebooks

Dialog notebooks can be opened as a separate window in the front end as a notebook or in-cell expression. Dialog notebooks are non-blocking dialogs that may or may not be modal.

Dialog notebook functions.

Here is a dialog that displays a notification or message.

CreateDialog[Column[{"The changes have been saved.",DefaultButton[]}]];

Set (RefLink[Modal, paclet:ref/Modal])->(RefLink[True, paclet:ref/True]) to make the same dialog modal.

CreateDialog[Column[{"The changes have been saved.",DefaultButton[]}],Modal->True];

Alternatively this creates an in-cell representation of the dialog notebook. A separate window containing the notebook can be opened in the front end by clicking the FEBitmapsManipulatePasteIcon button or wrapping (RefLink[CreateDialog, paclet:ref/CreateDialog]) around the (RefLink[DialogNotebook, paclet:ref/DialogNotebook]) expression.

DialogNotebook[Column[{"The changes have been saved.",DefaultButton[]}]]

Dialogs that display a message can also be created using (RefLink[MessageDialog, paclet:ref/MessageDialog]), which includes the (RefLink[DefaultButton, paclet:ref/DefaultButton]) by default.

MessageDialog["The changes have been saved."];

Here is a message dialog informing a user that a calculation is complete.

Mean@Transpose[FinancialData["DOW","Jan. 1, 2001"]][[2]]
MessageDialog["The calculation is complete."];

Sometimes it is useful to also include an audible beep with the message dialog using (RefLink[Beep, paclet:ref/Beep]).

Mean@Transpose[FinancialData["DOW","Jan. 1, 2001"]][[2]]
{Beep[],MessageDialog["The calculation is complete."]};

In addition to accepting input, dialog boxes can also evaluate expressions when they are closed. This can be done using (RefLink[DialogReturn, paclet:ref/DialogReturn]). Here is a modal dialog box that accepts user input and evaluates a variable assignment.

CreateDialog[Grid[{{"Last Name:",InputField[Dynamic[ln],String]},{"First Name:",InputField[Dynamic[fn],String]},{CancelButton[],DefaultButton[DialogReturn[name=StringJoin[ln,", ",fn]]]}},Spacings->{1,Automatic},Alignment->Left],Modal->True];

Type a first and last name into the input fields and click OK to assign the input values to name.

name

Several front end dialogs such as the the Wolfram System Preferences dialog were created using (RefLink[CreateDialog, paclet:ref/CreateDialog]).

Blocking Dialogs

The kernel in which blocking dialogs are evaluated is blocked until the dialog is closed.

Blocking dialog functions.

Block the kernel until val is set to 123.

val=DialogInput[Column[{"Value: 123",Button["Set",DialogReturn[123]]}]];

val

Here, the kernel is blocked until the user sets a value to removeQ by selecting Cancel or OK.

removeQ=DialogInput[Column[{"Do you want to continue?",Row[{CancelButton[DialogReturn["No"]],DefaultButton[DialogReturn["Yes"]]}]}]];

removeQ

Dialogs that display a choice can also be created using (RefLink[ChoiceDialog, paclet:ref/ChoiceDialog]), which blocks the kernel and returns (RefLink[False, paclet:ref/False]) if the (RefLink[CancelButton, paclet:ref/CancelButton]) is selected or (RefLink[True, paclet:ref/True]) if the (RefLink[DefaultButton, paclet:ref/DefaultButton]) is selected.

ChoiceDialog["Do you want to continue?"]

If the blocking dialog is thrown by a button or action menu, pass the button action along the main link to prevent timing out. This can be done by setting (RefLink[Method, paclet:ref/Method])->"Queued".

Button["Lorem Ipsum",ChoiceDialog["Do you want to continue?"],Method->"Queued"]

ActionMenu["Lorem Ipsum",{"dialog1":>ChoiceDialog["Do you want to continue?"],"print1":>Print["Lorem Ipsum"]},Method->"Queued"]

System Dialogs

The Wolfram Language also offers access to system dialogs through the use of (RefLink[SystemDialogInput, paclet:ref/SystemDialogInput]), front end tokens, and user interface-specific button functions including (RefLink[FileNameSetter, paclet:ref/FileNameSetter]), (RefLink[ColorSlider, paclet:ref/ColorSlider]), and (RefLink[ColorSetter, paclet:ref/ColorSetter]).

Accessing common system dialogs programmatically.

Here is the system file open dialog that returns the file path for the chosen file.

SystemDialogInput["FileOpen",WindowTitle->"Select a Notebook to Open"]

"FileSave" exhibits the same behavior as "FileOpen" by returning the file path for the chosen file.

SystemDialogInput["FileSave",WindowTitle->"Select a Notebook to Save"]

This opens the system color dialog and returns the (RefLink[RGBColor, paclet:ref/RGBColor]) value for the selected color.

SystemDialogInput["Color"]

The front end token "PrintDialog" opens the system print dialog and prints the notebook when the user selects Print.

FrontEndTokenExecute["PrintDialog"];

Accessing common system dialogs using existing button functions.

Here is a button that opens the system file open dialog and assigns the file path for the chosen file to a dynamic variable.

{FileNameSetter[Dynamic[a],"Open"],Dynamic[a]}

"OpenList" calls the system multiple file open dialog instead.

{FileNameSetter[Dynamic[b],"OpenList"],Dynamic[b]}

"Save" exhibits the same behavior as "Open" by assigning the file path for the chosen file to a dynamic variable.

{FileNameSetter[Dynamic[c],"Save"],Dynamic[c]}

This creates a button that opens the system directory picking dialog and assigns the file path for the chosen directory to a dynamic variable.

{FileNameSetter[Dynamic[d],"Directory"],Dynamic[d]}

Here is a color swatch that can be used to assign the value of a dynamic variable to an RGB color. Clicking the swatch will open the system color picker dialog.

{ColorSetter[Dynamic[e]],Dynamic[e]}

(RefLink[ColorSlider, paclet:ref/ColorSlider]) is a control object that contains the (RefLink[ColorSetter, paclet:ref/ColorSetter]) swatch as well as a color spectrum. Double-clicking the spectrum will open the system color picker dialog.

{ColorSlider[Dynamic[f]],Dynamic[f]}

Wolfram System Input Dialogs

The Wolfram Language usually works by taking whatever input it is given and then processing it. Sometimes, however, programs may need to explicitly request more input. This can be done using (RefLink[Input, paclet:ref/Input]) and (RefLink[InputString, paclet:ref/InputString]).

Requesting input dialogs.

(RefLink[Input, paclet:ref/Input])
 Dialog

This returns the polynomial expansion of the input.

Expand[Input["Enter a polynomial"]]

(RefLink[InputString, paclet:ref/InputString])
 Dialog

Here the inputted string is split into a list of substrings.

StringSplit[InputString["Enter a string"]]

Extended Examples

Progress Dialog

Here is a progress dialog that tracks the value of the dynamic variable n during a computation.

CreateProgressDialog[Dynamic[var_],{max_}]:=CreateDialog[Column[{"Calculation Progress:",Row[{ProgressIndicator[Dynamic[var],{1,max}]," ",Dynamic[Round@N[100 var/max]]," %"}]}],WindowSize->Fit]

nb=CreateProgressDialog[Dynamic[n],{175}];
Do[FactorInteger[2^n-1],{n,175}];
NotebookClose[nb];

Save Dialog

This is a modal dialog that will save the inputted notebook if the user selects Save or abort the operation if the user instead chooses Cancel.

SaveDialog[notebook_]:=CreateDialog[DynamicModule[{title=ToString[WindowTitle/.AbsoluteOptions[notebook,WindowTitle]]},Column[{Style["Do you want to save the changes you made in \nthe notebook '"<>title<>"'"<>" ?",Bold],"Your changes will be lost if you don't save them.",ChoiceButtons[{DialogReturn[NotebookSave[notebook,SystemDialogInput["FileSave",title]]],DialogReturn[$Canceled]}]},Spacings->1]],WindowTitle->"Save Changes...",Modal->True,WindowSize->{300,Fit}]

Find Dialog

This next example is a find dialog similar to those found in many applications.

CreateDialog[DynamicModule[{s="",dlg,s2="",ret,case=False},Column[{"Find this:",InputField[Dynamic[s],String],Dynamic[s2],Row[{Button["Find Next",dlg=SelectedNotebook[];s2="";
ret=NotebookFind[DeleteCases[Select[Notebooks[],(Options[#,StyleDefinitions]=!={StyleDefinitions->"Palette.nb"})&],dlg][[1]],s,Next,CellContents,IgnoreCase->case];
If[ret===$Failed,s2="No matches found."]],Button["Find Previous",dlg=SelectedNotebook[];s2="";
ret=NotebookFind[DeleteCases[Select[Notebooks[],(Options[#,StyleDefinitions]=!={StyleDefinitions->"Palette.nb"})&],dlg][[1]],s,Previous,CellContents,IgnoreCase->case];
If[ret===$Failed,s2="No matches found."]],Button["Find All",dlg=SelectedNotebook[];s2="";
ret=NotebookFind[DeleteCases[Select[Notebooks[],(Options[#,StyleDefinitions]=!={StyleDefinitions->"Palette.nb"})&],dlg][[1]],s,All,CellContents,IgnoreCase->case];
If[ret===$Failed,s2="No matches found."]]}],Row[{"Ignore Case  ",Checkbox[Dynamic[case]]}]},Automatic,.8]],WindowTitle->"Find..."];

Memory Usage Dialog

The Wolfram System can track the amount of memory being used by the front end and kernel processes at any given time. Here is a dialog that displays that data in real time.

DynamicModule[{memhistory},
memhistory=Join[Table[Null,{149},{2}],{N[{MemoryInUse[],MemoryInUse[$FrontEnd]}]}];CreateDialog[Dynamic[Row[{ListLinePlot[Tooltip[(First/@memhistory)/1024],PlotRange->{0,2*1048576.},PlotLabel->"Kernel Memory Usage (KB)",ImageSize->320,Axes->{False,True},AxesLabel->"KB",GridLines->{{15,30,45,60,75,90,105,120,135,150},Automatic},Frame->True],ListLinePlot[Tooltip[(Last/@memhistory)/1024],PlotRange->{0,2*1048576.},PlotLabel->"Front End Memory Usage (KB)",ImageSize->320,Axes->{False,True},AxesLabel->"KB",GridLines->{{15,30,45,60,75,90,105,120,135,150},Automatic},Frame->True]}]],WindowSize->{700,240},WindowTitle->"Memory Usage",NotebookDynamicExpression:>Dynamic[Refresh[If[Length[memhistory]<150,AppendTo[memhistory,N[{MemoryInUse[],MemoryInUse[$FrontEnd]}]],memhistory=Delete[memhistory,1];
AppendTo[memhistory,N[{MemoryInUse[],MemoryInUse[$FrontEnd]}]]],UpdateInterval->1,TrackedSymbols:>{}]]]];