10 Front End Programming: Mathematica User Interacts With Are Themselves Mathematica Expressions, All of The
10 Front End Programming: Mathematica User Interacts With Are Themselves Mathematica Expressions, All of The
In this chapter we extend the programming concepts we have covered thus far to the
objects that comprise the user interface, or front end. Because the objects that the
Mathematica user interacts with are themselves Mathematica expressions, all of the
tools that you use to do computations can also be used to create, manipulate, and alter
cells and notebooks themselves. We will first look at the underlying structure of these
objects and then discuss ways of manipulating them directly from within Mathematica.
10.1 Introduction
Up until this point, we have been primarily concerned with learning about programming
constructs and styles so that we can write programs to manipulate data or solve problems
from science, engineering, or mathematics. We have taken for granted that the space in
which we do our experimenting, prototyping, and documenting has been the Mathematica
notebook, an interface that has some similarities to a word processor document.
It is not uncommon now to add interactive elements to your documents to make
them more useful for yourself or the intended reader of your documents. With programs,
documentation, and papers all being created and used in electronic format, Mathematica
provides a seamless and well-integrated interface to these elements.
Another tool that is useful, especially for educators, are buttons that allow you to
hide your program code behind a familiar and easy-to-use interface element the button.
The user clicks on a button and an action happens that is determined by the underlying
code. For example, you might want to have calculus students quickly plot Taylor polynomial approximations to a function together with the original function but do not want
them to spend time learning the syntax of such commands in Mathematica. You could
easily program an interface that would only require them to fill in a few parameters before
clicking a button to produce the desired plot.
In this chapter we will discuss the structure of cell and notebook expressions, look at
a few basic functions for manipulating these expressions, and then create several simple
examples that give a flavor of the kind of things that can be done with front end
programming.
312
Before we begin we should mention that this chapter is not intended as a complete
discussion of front end programming. An entire book could certainly be written on this
topic alone. This book is intended to give you an introduction to the many aspects of
programming with Mathematica and front end programming is certainly an appropriate
topic for that introduction. But there are several areas that cannot be included here, either
because of space limitations or because they do not fit under the introductory nature of
this book. These topics include front end options and front end tokens. An understanding
of each of these topics is quite important for more advanced front end programming. The
interested reader can delve further into this subject by looking in the Front End category
of the Help Browser or by searching the Mathematica Information Center online at
library.wolfram.com/infocenter.
Notebook expressions
Notebooks are ASCII files, meaning that you can open them in a text editor and view their
contents directly. If you were to do that, you would see that the underlying expression is a
Mathematica function called a Notebook. The notebook would look like this:
Notebook[{
Cell[string,style,options],
Cell[string,style,options],
},
options]
In other words, the Notebook is a function whose first argument is a list of one or
more Cell objects, followed by some options. The Mathematica kernel does not do
313
anything with this practically. It is the Mathematica front end that knows how to render
this expression as the familiar notebook.
For example, here is a very simple notebook that you could write in a text editor (of
course there is no reason to do that).
Notebook[{
Cell["Demo notebook", "Section"],
Cell["This is a text cell.","Text"],
Cell["1+2+3", "Input"]
}]
The Mathematica front end renders this expression in the familiar manner, a window.
Let us create the notebook from scratch using a kernel command, NotebookPut.
NotebookPut[expr] will create a notebook corresponding to expr in the front end and
make it the currently selected notebook.
NotebookPut
Notebook
Cell "Demo notebook", "Section" ,
Cell "This is a text cell", "Text" ,
Cell "1 2 3", "Input"
Untitled 1
+ +
@
@
@
D<
NotebookObject
8@
Out[1]=
nb
In[1]:=
314
There is actually quite a lot going on behind the scenes here in terms of the interaction between the kernel and the front end. As stated in Chapter 1, the kernel and the front
end are two separate programs that communicate with each other through a protocol
called MathLink. For purposes of efficiency, MathLink itself does not store the notebook in
memory but instead refers to it by means of a handle. These handles are called notebook
objects and are given as NotebookObject[fe,id], where fe is an object that refers to the
entire front end and id is an integer that is a unique identifier for that notebook. In the
example above, looking at the InputForm displays this information stored with the
notebook object.
InputForm nb
D @
In[2]:=
Out[2]//InputForm=
NotebookObject[FrontEndObject[LinkObject["3v8_shm",
1, 1]], 28]
Since we have assigned a symbol, nb, to this object, we can refer to it through this
symbol. NotebookGet gets the expression corresponding to this notebook and reads it
into the kernel. You should think of it as analogous to Get for packages.
Notebook
Cell CellGroupData Cell Demo notebook, Section , Cell
This is a text cell, Text , Cell 1 2 3, Input , Open
FrontEndVersion 5.0 for Microsoft Windows,
ScreenRectangle
0., 1024. , 0., 681.
<DD
<D
++@
D<<
8 <
8@
88
Out[3]=
NotebookGet nb
D @
In[3]:=
Notice that the front end has added two options to this notebook: FrontEndVer
sion and ScreenRectangle. It has also added some grouping information for the cells.
315
These are default behaviors of the front end and may vary from one front end to another.
They are also user-settable.
Manipulating notebooks
NotebookPut and NotebookGet are general functions for dealing with entire notebooks at once. There are a host of additional functions for manipulating parts of notebooks. You might first think that we can simply use functions like Part to extract a
particular part of a notebook we are interested in. There are several reasons why this is not
generally practical. First, because a notebook can contain many, many cells, it is often
quite difficult to determine precisely which part you want to work on. Secondly, since the
notebook resides in the front end, not the kernel, it is often not very efficient to manipulate the notebook directly by the kernel (although, if the notebook is small enough, this is
certainly possible).
As it turns out, there is a way around these issues and that is through something
referred to as the current selection, which is essentially a reference to the notebook
object. You could then think of the notebook manipulation functions as operating on
streams.
To see a list of the open notebooks, use Notebooks[].
Untitled 1
,
10FEProgramming.nb
Messages
<D
NotebookObject
NotebookObject
NotebookObject
@
@
@
Out[4]=
Notebooks
D@
In[4]:=
Again, using InputForm, you can see the actual handles to each of the notebooks.
Notebooks
D@
In[5]:=
InputForm
Out[5]//InputForm=
{NotebookObject[FrontEndObject[LinkObject["3v8_shm",
1, 1]], 28], NotebookObject[
FrontEndObject[LinkObject["3v8_shm", 1, 1]], 27],
NotebookObject[FrontEndObject[LinkObject["3v8_shm",
1, 1]], 7]}
Let us walk through some of the most common notebook operations you should
learn about. The first is NotebookCreate. As its name implies, this function will create a
new untitled notebook in the front end. We assign nb to be the handle to this notebook.
316
NotebookCreate
NotebookObject
Untitled 2
Out[6]=
nb
D@
In[6]:=
Now let us write to the notebook. NotebookWrite takes two arguments: the first
argument is the notebook object that we are writing to; the second argument is what we
are writing. We will create a few different examples below.
A Cell is an expression with two arguments. The first argument is the contents of
the cell; the second argument is the cell style, a listing of which is under the Format Style
menu in the front end.
DD
In[7]:=
317
Adding options to Cell allows us to change some of the properties of the cell. For
example, here are several of the options that you can add.
NotebookWrite nb,
Cell "Here is some more text.", "Text",
CellFrame True, CellDingbat
<
DD
In[9]:=
Deletable
CellFrame
8 D
Out[8]=
D<
In[8]:=
In[10]:=
318
Now suppose we wanted to insert an input cell with the expression 2100 in it.
In[11]:=
Out[11]=
2100
1267650600228229401496703205376
If you were to look at the underlying expression of the above cell (under the Format
menu, choose Show Expression), it would look like this:
Cell[BoxData[
SuperscriptBox["2", "100"]], "Input"]
We will talk about BoxData in just a moment, but we should be able to insert a cell
like this directly into our notebook object. Before we do this, notice that the insertion
point has been left inside the Input cell after the last NotebookWrite. To move the cell
insertion bar after the current cell, we will use SelectionMove which takes three arguments: the notebook we are operating on, the direction to move, and the unit by which we
should move. The direction can be any of Next, Previous, After, Before, All. The
units are things like Word, Cell, CellGroup, Notebook (see the Help Browser under
SelectionMove for a complete description).
So, in our example, we want to move the selection just after the present cell.
SelectionMove nb, After, Cell
In[12]:=
319
, "Input"
DD
DD
@
@
In[13]:=
Notice that at the end of each NotebookWrite, the cell insertion bar was placed
just after the cell that was written, except in the case of writing input cells. Oftentimes, you
will need to move around within the notebook or select a particular cell (or other expression) and perform some operation on it. For example, suppose we would like to select the
previous cell (the one containing the 2100 ) in nb and evaluate it. We can do this with the
SelectionMove function.
SelectionMove nb, Previous, Cell
In[14]:=
320
D @
In[15]:=
Let us put a few of these pieces together and create a function that will evaluate the
next input cell. In Section 10.5 we will turn this code into a button.
For this example we will operate in the current notebook. We can refer to the
notebook in which these commands are being evaluated by EvaluationNotebook[].
First we select the current unit; that is, the cell in which the following code lives.
SelectionMove[EvaluationNotebook[],All,Cell]
Then we move the selection insertion to the next cell (at the moment, this code will only
work if it is immediately followed by an input cell).
SelectionMove[EvaluationNotebook[],Next,Cell]
321
D
D
DD@
D@
D@
@
@
H=
In[16]:=
Evaluating the cell containing EvaluateNext causes the immediately following cell to be
evaluated.
In[17]:=
EvaluateNext
In[18]:=
Out[18]=
Exercises
1. Using NotebookPut, create a notebook with one Title cell, one Section cell, one
Then programmatically change the Section cells to Subsection cells either using
Cases or an appropriate rule.
3. Take either of the notebooks you created in the above exercises and use Selection
Move and SelectionEvaluate to evaluate all of the Input cells in the notebook.
322
TextData
Let us first look at a text cell that contains no special formatting.
Cell["Here is some text.", "Text"]
323
Cell[TextData[{
"The current date is: ",
ValueBox["DateLong"]
}], "Text"]
BoxData
Many of your cells in Mathematica will contain formatted mathematical expressions.
Whenever you work with these two-dimensional typeset objects, a different editor is
invoked, called the math editor. This is indicated in the front end by a pink background in
Text cell style on the typeset expression (you can enter a math typeset expression by
pressing Control-9). This is also indicated in the underlying cell structure by means of the
BoxData wrapper. For example, consider the following cell containing a superscript
expression.
Cell[BoxData[
RowBox[{
SuperscriptBox["x", "2"], "+", "y"}]], "Input"]
x2
There are several things to note here. First, we see that Mathematica has automatically placed the elements x2 , + and y all in something called a RowBox. This is how Mathematica represents box objects or a series of strings.
Secondly, the x2 object is represented internally as another box object, specifically
SuperscriptBox[x,2]. You can use DisplayForm to print box expressions in an
explicit two-dimensional form.
SuperscriptBox x, 2
Out[1]//DisplayForm=
x2
In[1]:=
DisplayForm
324
There are many different box objects in Mathematica. Below are just a few commonly
used box objects.
Cell[BoxData[
SqrtBox["2"]], "Input"]
!!!!
2
Cell[BoxData[
FractionBox["x", "y"]], "Input"]
Cell[BoxData[
RowBox[{
SubsuperscriptBox[" ", "a", "b"],
RowBox[{"x", " ",
RowBox[{" ", "x"}]
}]
}]
], "Input"]
x x
a
GraphicsData
Another type of data wrapper that you will encounter is GraphicsData, used to indicate
a graphical object in the cell. For example, creating a graphics object in the front end
displays a plot.
325
Plot Sin x , x, 0, 2
D<
8 D @
In[2]:=
0.5
0.5
If you unformat the graphics cell, the first few lines would look like the following:
Cell[GraphicsData["PostScript", "\<\
%!
%%Creator: Mathematica
%%AspectRatio: .61803
MathPictureStart
...
Normally you will not create graphics objects from scratch so it would seem as if
there is not too much you could do with GraphicsData objects manually. But suppose
you were interested in displaying your graphics to a notebook other than the one in which
you evaluate the graphics input. For example, we could use NotebookPut to write out a
new notebook containing a graphics cell object as follows:
DD<D
MyDisplayChannel gr_ :
NotebookPut Notebook Cell GraphicsData
"PostScript", DisplayString gr , "Graphics"
DD @
= D
8@
In[3]:=
Untitled 5
8 D
NotebookObject
8 <
Out[4]=
Plot3D Sin x y , x, 0, 2 , y, 0, 2
DisplayFunction MyDisplayChannel
D
<
In[4]:=
Evaluating the above expression will cause a new notebook window to be created in
your front end containing just the output of the Plot3D command, a graphic of the
surface sin x y .
L
326
Exercises
1. Using NotebookPut, create a notebook with several Text cells each containing a
uate.
10.4 GridBoxes
ShowTable
Whenever you create a two-dimensional expression consisting of some number of rows
and columns, Mathematica represents that expression as a GridBox object. For example, if
you used the BasicInput palette to create a 2 2 matrix, it would be represented as follows:
Cell[BoxData[GridBox[{
{"a", "b"},
{"c", "d"}
}]], "Input"]
Looking at the GridBox object, you should see that it is identical (structurally) to a
matrix in Mathematica, which is really just a list of lists.
FullForm
a b
c d
In[1]:=
Out[1]//FullForm=
8 <
88
a b
c d
<<
Out[2]//MatrixForm=
a, b , c, d
DD
In[2]:=
MatrixForm
327
Using GridBoxes, let us create a function for displaying arrays of data in a formatted table. First we create some sample data.
" ", " ", " " ,
x
89 =
", "
y
n "
== L H
data
<
9 <
In[3]:=
We can put this data into a GridBox and immediately print it in a two-dimensional
grid using DisplayForm.
GridBox data
In[4]:=
DisplayForm
Out[4]//DisplayForm=
!!
!
L H
x
y
<<
<
8 <
<
88
8
Out[5]=
Options GridBox
In[5]:=
Let us add a frame, make the margins around each grid element a bit larger than the
default, and add some lines between the rows and columns. Usually you will set the values
for GridFrame, RowLines, and ColumnLines to either True or False to enable or
disable these elements. Giving an explicit number as the value of each of these options
gives the thickness of the line that is drawn for that object.
GridBox data,
GridFrame 1.2, GridFrameMargins
1, 1 , 1, 1
RowLines 1, ColumnLines 1
DisplayForm
8 <
88
Out[6]//DisplayForm=
<<
In[6]:=
!!!
!
L H
x
y
Now we can bundle up this code and turn all of it into a function, ShowTable. If we
wish, we can add some formatting, but to do so we have to wrap the GridBox in a Style
328
In[8]:=
ShowTable data
<<
8 <
= D
88
D @
DD
Out[8]//DisplayForm=
g
x
y
HG
! !!
!
Sometimes the data you work with will need to be manipulated in some way to
display it. The following is another example of the use of ShowTable, but one for which
we first need to think about the dimensions of our data. Consider displaying a table of
reciprocals of rep units, numbers consisting entirely of 1s.
1 &, 1, n
= D
In[9]:=
1
Map
&, Range 12
RepUnit #
D @
Out[10]=
expr
ED @
In[10]:=
1
1
1
1
1
1
1
,
,
,
,
,
,
,
11
111
1111
11111
111111
1111111
11111111
1
1
1
1
,
,
,
111111111
1111111111
11111111111
111111111111
1,
DD
In[11]:=
Out[11]//DisplayForm=
1
111
1
111111
1
111111111
1
111111111111
1
1111
1
1111111
1
1111111111
1
11
1
11111
1
11111111
1
11111111111
329
DD
In[12]:=
Out[12]//DisplayForm=
1
1111
1
11111111
1
111111111111
1
11111
1
111111111
1
111
1
1111111
1
11111111111
1
11
1
111111
1
1111111111
In the above tables, we are manually partitioning the rows and columns into sublists
that will be rectangular when they are put into the table. It would be good programming
style to take that task from the user and do it automatically. We leave this as an exercise.
TriangleForm
In this section we will use GridBox to develop a function for displaying an array in a
triangular format. Such a function is quite useful for displaying the elements of Pascals
triangle in the familiar triangular array.
1
1
1
1
1
1
1
1
10
15
10
35
56
1
4
20
21
28
1
3
7
8
3
4
1
2
5
15
35
70
1
6
21
56
1
7
28
1
8
First let us create a function for generating the first n rows of Pascals triangle.
PascalTable rows_ :
Table Binomial n, m , n, 0, rows , m, 0, n
= D
8 <
8 D
Here are the first four rows (including the 0th row).
PascalTable 3
1 , 1, 1 , 1, 2, 1 , 1, 3, 3, 1
<<
8 <
8 <
8 < 88
Out[14]=
expr
D @
In[14]:=
D<
In[13]:=
330
If we put empty strings around the elements in the appropriate places we can see
what the grid should look like.
GridBox
"", "", 1, "", "" ,
"", 1, "", 1, "" ,
1, "", 2, "", 1
DisplayForm
<
8@
<
<
In[15]:=
D<
8
8
8
Out[15]//DisplayForm=
1
1
1
1
2
So we need to develop a function to insert these empty strings between each element
in each row and we also need to pad out each row to the length of the longest row in the
entire table. First we write the function to pad each row.
= D
@
@
H@
DDD @@
, , , 1, , ,
2
DDD @@
, , , 1, 1, ,
<
pad expr
<
Out[18]=
In[18]:=
Out[17]=
pad expr
In[17]:=
DD LD
In[16]:=
Now to insert the appropriate number of empty strings between elements, let us first
manually insert space in a few rows.
2
, "",
, "",
, "",
DD @@
1, , 1
<
Out[19]=
Insert expr
D<< 88
In[19]:=
Insert expr
Out[20]=
1, , 2, , 1
<
Insert expr
2 , 3 , 4
DD @@
1, , 3, , 3, , 1
<
Out[21]=
DD @@
In[21]:=
2 , 3
D<< 8 < 88
In[20]:=
2 , 3 , 4
1, 3, 3, 1
8@
Out[22]=
DDDD<
In[22]:=
331
Here is the function to add the appropriate amount of space between elements in
each row.
In[23]:=
addspace lis_ :
Insert lis, "", Map List, Rest Range Length lis
In[24]:=
addspace expr
= D
DDD @@
1, , 2, , 1
<
addspace expr
DDD @@
< 8
Out[25]=
In[25]:=
DDDDD
Out[24]=
This maps the addspace function across each row of the Pascal table.
Map addspace, PascalTable 3
1 , 1, , 1 , 1, , 2, , 1 , 1, , 3, , 3, , 1
<<
8 <
8 <
8 < 88
Out[26]=
expr
DD @
In[26]:=
Then we pad out each row using our pad function developed above.
, , , 1, , , , , , 1, , 1, , ,
, 1, , 2, , 1, , 1, , 3, , 3, , 1
<
<<
8 <
8 <
8
88
Out[27]=
In[27]:=
D @
In[28]:=
DisplayForm
Out[28]//DisplayForm=
1
1
1
1
TriangleForm lis_List :
Module addspace, expr, len
<D
= D
8A
addspace l_ :
Insert l, "", Map List, Rest Range Length l
;
expr Map addspace, lis ;
DisplayForm GridBox Map PadLeft #, 2 len 1,
1
"", Round
2 len 1 Length #
&, expr
2
DDDDD @
EE
EELD @
A
D
= D @
E
E
In[29]:=
332
PascalTable 5
D @
In[30]:=
TriangleForm
Out[30]//DisplayForm=
1
1
1
1
1
3
4
1
3
6
10
4
10
1
5
Exercises
1. Modify ShowTable so that it can display a user-specified heading in the first row of
the grid. Include formatting to set the style of the strings in the heading to be different than the rest of the elements displayed by ShowTable.
2. Modify ShowTable so that it automatically partitions the list it is passed to be
rectangular, with the number of rows and columns as close to each other as possible.
3. Create a function TruthTable[expr,vars] that displays the logical expression expr
together with all the possible truth values for the variables in the list vars. For example, here is the truth table for the expression A B
C.
L
B, C , A, B, C
D<
8 D
TruthTable Implies A
In[1]:=
Out[1]//DisplayForm=
C
T
F
T
F
T
F
T
F
B
T
T
F
F
T
T
F
F
A
T
T
T
T
F
F
F
F
B
T
F
T
F
T
F
T
T
You will first need to create a list of all possible truth value assignments for the
variables, A, B, C in this case. One approach would be to use Distribute. So,
essentially, this is the left-hand side, or first three columns of the above table (not
counting the first row containing the table headings).
333
D<
<
8@
<
8=
@
@
<
<
<<
8 <
8 <
8 <
8 <
8 <
8
8
88
Out[3]=
len
vars
A, B, C ;
len Length vars ; ins
Distribute Table True, False ,
In[2]:=
You can then create a list of rules associating each of these triples of truth values with
a triple of variables.
<
<
<
<
8<
8<
8<
<<
A
A
A
A
A
#1 &, ins
8
8
8
8
88
Out[4]=
In[4]:=
Substituting these rules into the logical expression produces a truth value for each of
the above rows.
. Map Thread vars
B, C
#1 &, ins
<
Out[5]=
Implies A
In[5]:=
Your task is to put all these pieces together in a GridBox with appropriate
formatting.
10.5 Buttons
Buttons are very user-friendly objects whose functionality is familiar to any computer user.
From the programmers point of view, they allow you to hide your code behind a graphical
element, the button. Instead of writing a function and evaluating it by pressing Shift-Enter
from the keyboard, you pass the mouse cursor over the button and simply click. Whatever
code is hidden underneath the button is then evaluated.
In this section we will first look at the structure of ButtonBoxes and then create
some examples to demonstrate the variety of tasks that can be accomplished with buttons.
334
<
<
a1 , a2 , , an
a1 , a2 , , an
Finally, to activate the button so that you can click it to have an action occur, select
the cell in which the button occurs and then choose Cell Properties Cell Active from the
Cell menu.
<
a1 , a2 , , an
Clicking the above button will paste the following at the insertion point:
a1 , a2 , , an .
If you wished, you could create a free-standing palette from this button by choosing
Generate Palette from Selection from the File menu.
Although the above procedure for creating buttons is quite straightforward, it is only
convenient for fairly simple buttons. For more complicated buttons you will find that you
need a good understanding of the structure of buttons and the various options that control
their actions and display. We turn to those topics in the next few sections.
<
335
Out[1]//DisplayForm=
True
In[1]:=
DisplayForm
some text
Note that we have added the option Active True. This makes the resulting
button uneditable, one that is clickable. You will need to add this option to all your buttons to activate them. Clicking this button causes the following to be pasted at the current
selection point.
some text
Let us create a button that can serve as a template for a definite integral.
In[2]:=
ButtonBox["Integrate[fun,{x,xmin,xmax}]", Active->True]
//DisplayForm
Out[2]//DisplayForm=
D<
D<
We can use placeholders in our template button so that the user can move from one
can be
placeholder to the next by pressing the Tab key. The placeholder character
entered either from the Complete Characters palette (look under Letter-like Forms and
-sp(pressing the
then Keyboard Forms), or directly from the keyboard by typing
Escape key, then the characters s and then p, and finally the closing Escape key).
In[3]:=
Out[3]//DisplayForm=
, ,
D<
Integrate
Clicking on this button causes the following expression to be pasted. You can move
from one placeholder to another by pressing the Tab key.
, ,
D<
Integrate
336
ButtonStyle
Although having buttons that paste their contents at the current selection point is useful,
there is much more that buttons can do. For example, they can wrap the contents of the
ButtonBox around a selected expression and then evaluate that expression. To change
the default behavior of buttons from simply pasting their contents to other actions, we
have to use the ButtonStyle option. ButtonStyle is used to control both the style
and the actions associated with your buttons. In the following example, ButtonStyle is
set to CopyEvaluateCell.
True,
DisplayForm
In[4]:=
The character is entered either from palettes or directly from the keyboard by
typing -spl- . Evaluating the above input produces the cell below. Selecting the input
x5 and then clicking the button causes the template to be
cell containing Cos x2
wrapped around the selected expression and then it is evaluated.
+D @
Out[4]//DisplayForm=
,x
Integrate
In[6]:=
Integrate Cos x2
%%%%%%%$
2
FresnelC
x5 , x
2
E %%%%%%%$A
x6
6
+D @
+D @
Out[6]=
x5
Cos x2
In[5]:=
Cell[TextData[{
"Search for button on ",
ButtonBox["Google",
ButtonData:>{
URL[ "http://www.google.com"], None},
ButtonStyle->"Hyperlink"]
}], "Text"]
337
Action
Paste
Evaluate
EvaluateCell
CopyEvaluate
ButtonFunction
Whenever you need to put some Mathematica code inside your button, you will need to do
so as the value of the option ButtonFunction. You will also need to explicitly set the
option ButtonEvaluator which is set to None by default. The ButtonEvaluator
option tells the front end what program it should communicate with to process the contents of the button function. Setting it to None tells the front end to communicate with
itself which is fine for operations like copying and pasting. But for operations that need to
communicate with a kernel, you will have to specify that explicitly. A value of Automatic
sends the code to the default kernel for the current notebook. If you had other kernels set
up, you could direct the button function at one of those.
338
D
D @
In[7]:=
Out[7]//DisplayForm=
Compute 5
Clicking this button will not cause any output to be displayed. This is because these
buttons are not evaluated in the kernel in the usual way as part of the main loop. In this
case, you can use Print to see the side effect of this computation.
ButtonBox "Compute 5 ",
Active True,
ButtonFunction Print Factorial 5 ,
ButtonEvaluator Automatic
DisplayForm
120
Compute 5
Out[8]//DisplayForm=
DD @
In[8]:=
You can use any Mathematica function you wish as the value of the ButtonFunc
tion option. But, in addition to the above issue with displaying output, you should be
aware of another important issue. As it turns out, the front end does not know how to
parse the special shorthand notation we often use for arithmetic and other operations. You
will be forced to use the FullForm of such expressions inside of your ButtonFunc
tion. So instead of 2+2, use Plus[2,2]; instead of {<<Graphics`; LogPlot[
Exp[x],{x,1,2}]} use CompoundExpression[Get["Graphics`", LogPlot[
Exp[x],{x,1,2}]]. Fortunately, the parser for the front end can recognize the shorthand notation for List, Rule, and RuleDelayed, so you can use the shorthand notations {}, , and , respectively.
As a final example, we will create a button that loads a package and then performs a
computation with some functions from that package. Here is the code that we want to
encapsulate in our button.
Needs "Graphics`Polyhedra`"
In[9]:=
339
DDDD@
In[10]:=
Here is the button code. Note that we have also added an option to ButtonBox to
set the background and set the entire cell to use the Times font family.
Cell[BoxData[
ButtonBox[RowBox[{"Stellate"," ","Icosahedron"}],
ButtonFunction->
CompoundExpression[Needs["Graphics`Polyhedra`"],
Show[Graphics3D[Stellate[Icosahedron[]]]]],
ButtonEvaluator->Automatic,
Background->GrayLevel[.5]]],
"Input",Active->True,
FontFamily->"Times",
FontColor->GrayLevel[1]]
Stellate Icosahedron
340
To put this code inside a button, we need to make a few modifications. First, remember that the front end does not know how to parse shorthand notation such as ;. Instead
we need to use CompoundExpression. Second, instead of EvaluationNotebook, we
will use ButtonNotebook, which gives the notebook in which the current button lives.
Finally, we need to use ButtonCell to refer to the cell containing the button itself.
Putting all these pieces together, here is the ButtonFunction.
ButtonFunction CompoundExpression
SelectionMove ButtonNotebook , All, ButtonCell ,
SelectionMove ButtonNotebook , Next, Cell ,
SelectionEvaluate ButtonNotebook
;
D<DD@
@
@
Cell[TextData[{
Cell[BoxData[
ButtonBox["EVALUATE",
ButtonFunction:>CompoundExpression[ {
SelectionMove[
ButtonNotebook[ ], All, ButtonCell],
SelectionMove[
ButtonNotebook[ ], Next, Cell],
SelectionEvaluate[
ButtonNotebook[ ]]}],
Active->True]]],
" MATHEMATICA INPUT"
}], "Text"]
D@
D@
In[13]:=
341
And here is the formatted button. Clicking the Evaluate button causes the cell just
below the button cell to be evaluated.
EVALUATE MATHEMATICA INPUT
2
Out[14]=
In[14]:=
Finally, let us add some formatting to make this cell a little nicer looking.
Cell[TextData[{
Cell[BoxData[
ButtonBox[
StyleBox["EVALUATE",
FontFamily->"Helvetica",
FontSize->10,
FontWeight->"Bold"],
ButtonFunction:>CompoundExpression[ {
SelectionMove[
ButtonNotebook[ ], All, ButtonCell],
SelectionMove[
ButtonNotebook[ ], Next, Cell],
SelectionEvaluate[
ButtonNotebook[ ]]}],
Active->True,
Background->GrayLevel[0.500008]]]],
StyleBox[" MATHEMATICA INPUT",
FontFamily->"Helvetica",
FontSize->10,
FontWeight->"Bold",
FontSlant->"Italic",
FontColor->GrayLevel[1]]
}], "Text",
Background->GrayLevel[0.500008]]
Here is the formatted version of this code with the result of clicking the button.
EVALUATE MATHEMATICA INPUT
Out[15]=
In[15]:=
There is a little inefficiency in our code as we are calling the kernel several times (two
instances of SelectionMove and one of SelectionEvaluate) for what are essen-
342
tially front end operations, moving and selecting. You can send these sorts of commands
directly to the front end by wrapping them in FrontEndExecute. To distinguish
between the kernel command and the front end command you also need to append the
FrontEnd` context to the function. So for example, instead of using Selection
Move[] in the kernel, you can send it directly to the front end with the following.
FrontEndExecute[FrontEnd`SelectionMove[]]
With this in mind, the EVALUATE button can be rewritten by only changing the
ButtonFunction.
ButtonFunction:>FrontEndExecute[ {
FrontEnd`SelectionMove[
ButtonNotebook[ ], All, ButtonCell],
FrontEnd`SelectionMove[
ButtonNotebook[ ], Next, Cell],
FrontEnd`SelectionEvaluate[
ButtonNotebook[ ]]}]
Another method of directly accessing front end commands is via front end tokens.
These tokens allow you to perform any menu command directly from the kernel. We will
not discuss them here, but for a detailed discussion of front end tokens, see the Front End
category of the Help Browser.
Exercises
1. Create a button that will serve as a template for the Plot3D function.
2. Create a button that will wrap Expand[] around any selected expression and
Exercise 2. Include in your palette a button for each of Expand, Factor, Apart,
and Together.