<#30338#>Figure: The model-view arrangement<#30338#> <#30794#>Real-world GUIs<#30794#>:\ The graphical user interface in
figure~#figlookupgui#30795>
The ideal program consists of two completely separate components: the
<#65696#><#30340#>MODEL<#30340#><#65696#>, which is the kind of program we are learning to design,
and a <#65697#><#30341#>VIEW<#30341#><#65697#>, which is the GUI program that manages the display of
information and the user's mouse and keyboard manipulations. The bridge
between the two is the <#65698#><#30342#>CONTROL<#30342#><#65698#> expression. Figure~#figmvc#30343> A <#65700#><#30347#>gui-item<#30347#><#65700#> is either
<#71390#>;; <#65705#><#30369#>create-window<#30369#> <#30370#>:<#30370#> <#30371#>(listof<#30371#> <#30372#>(listof<#30372#> <#30373#>gui-item))<#30373#> <#30374#><#30374#><#30375#>-;SPMgt;<#30375#><#30376#><#30376#> <#30377#>true<#30377#><#65705#> <#71390#>
<#30378#>;; to add gui-items to the window and to show the window<#30378#>
<#30379#>;; each list of gui-items defines one row of gui items in the window<#30379#>
<#71391#>;; <#65706#><#30380#>hide-window<#30380#> <#30381#>:<#30381#> <#30382#><#30382#><#30383#>-;SPMgt;<#30383#><#30384#><#30384#> <#30385#>true<#30385#><#65706#> <#71391#>
<#30386#>;; to hide the window<#30386#>
<#71392#>;; <#65707#><#30387#>make-button<#30387#> <#30388#>:<#30388#> <#30389#>string<#30389#> <#30390#>(event%<#30390#> <#30391#><#30391#><#30392#>-;SPMgt;<#30392#><#30393#><#30393#> <#30394#>true)<#30394#> <#30395#><#30395#><#30396#>-;SPMgt;<#30396#><#30397#><#30397#> <#30398#>gui-item<#30398#><#65707#> <#71392#>
<#30399#>;; to create a button with label and call-back function <#30399#>
<#71393#>;; <#65708#><#30400#>make-message<#30400#> <#30401#>:<#30401#> <#30402#>string<#30402#> <#30403#><#30403#><#30404#>-;SPMgt;<#30404#><#30405#><#30405#> <#30406#>gui-item<#30406#><#65708#> <#71393#>
<#30407#>;; to create an item that displays a message<#30407#>
<#71394#>;; <#65709#><#30408#>draw-message<#30408#> <#30409#>:<#30409#> <#30410#>gui-item[<#30410#><#30411#>message%<#30411#><#30412#>]<#30412#> <#30413#><#30413#><#30414#>-;SPMgt;<#30414#><#30415#><#30415#> <#30416#>true<#30416#><#65709#> <#71394#>
<#30417#>;; to display a message in a message item <#30417#>
<#30418#>;; it erases the current message <#30418#>
<#71395#>;; <#65710#><#30419#>make-text<#30419#> <#30420#>:<#30420#> <#30421#>string<#30421#> <#30422#><#30422#><#30423#>-;SPMgt;<#30423#><#30424#><#30424#> <#30425#>gui-item<#30425#><#65710#> <#71395#>
<#30426#>;; to create an item (with label) that allows users to enter text<#30426#>
<#71396#>;; <#65711#><#30427#>get-text<#30427#> <#30428#>:<#30428#> <#30429#>gui-item[<#30429#><#30430#>text%<#30430#><#30431#>]<#30431#> <#30432#><#30432#><#30433#>-;SPMgt;<#30433#><#30434#><#30434#> <#30435#>string<#30435#><#65711#> <#71396#>
<#30436#>;; to determine the contents of a text field <#30436#>
<#71397#>;; <#65712#><#30437#>make-choice<#30437#> <#30438#>:<#30438#> <#30439#>(listof<#30439#> <#30440#>string)<#30440#> <#30441#><#30441#><#30442#>-;SPMgt;<#30442#><#30443#><#30443#> <#30444#>gui-item<#30444#><#65712#> <#71397#>
<#30445#>;; to create a choice menu that permits users to choose from some<#30445#>
<#30446#>;; string alternatives <#30446#>
<#71398#>;; <#65713#><#30447#>get-choice<#30447#> <#30448#>:<#30448#> <#30449#>gui-item[<#30449#><#30450#>choice%<#30450#><#30451#>]<#30451#> <#30452#><#30452#><#30453#>-;SPMgt;<#30453#><#30454#><#30454#> <#30455#>num<#30455#><#65713#> <#71398#>
<#30456#>;; to determine which choice is currently selected in a choice-item <#30456#>
<#30457#>;; the result is the 0-based index in the choice menu <#30457#>
<#65714#>Figure: The <#30461#>gui.ss<#30461#> operations<#65714#>
Here we study the simplified GUI world of the teachpack
<#30463#>gui.ss<#30463#>. Figure~#figguitp#30464>
The function that goes with a button is a function of one argument: an
event. For most uses, we can ignore the event; it is simply a token that
signals the user's click action.
How all this works is best illustrated with examples.
Our first example is a canonical GUI program:
<#30488#>(create-window<#30488#> <#30489#>(list<#30489#> <#30490#>(list<#30490#> <#30491#>(make-button<#30491#> <#30492#>``Close''<#30492#> <#30493#>hide-window))))<#30493#>
It creates a window with a single button and equips it with the simplest of
all call-backs: <#65723#><#30497#>hide-window<#30497#><#65723#>, the function that hides the window. When
the user clicks the button labeled <#65724#><#30498#>``Close''<#30498#><#65724#>, the window disappears.
The second sample GUI copies what the user enters into a <#30499#>text<#30499#> field to a
<#30500#>message<#30500#> field. We first create a <#30501#>text<#30501#> field and a <#30502#>message<#30502#> field:
<#30507#>(d<#30507#><#30508#>efine<#30508#> <#30509#>a-text-field<#30509#>
<#30510#>(make-text<#30510#> <#30511#>``Enter<#30511#> <#30512#>Text:''))<#30512#>
<#30513#>(d<#30513#><#30514#>efine<#30514#> <#30515#>a-message<#30515#>
<#30516#>(make-message<#30516#> <#30517#>```<#30517#><#30518#>Hello<#30518#> <#30519#>World'<#30519#> <#30520#>is<#30520#> <#30521#>a<#30521#> <#30522#>silly<#30522#> <#30523#>program.''))<#30523#>
Now we can refer to these fields in a call-back function:
<#71400#>;; <#65725#><#30531#>echo-message<#30531#> <#30532#>:<#30532#> <#30533#>X<#30533#> <#30534#><#30534#><#30535#>-;SPMgt;<#30535#><#30536#><#30536#> <#30537#>true<#30537#><#65725#><#71400#>
<#71401#>;; to extract the contents of <#65726#><#30538#>a-text-field<#30538#><#65726#> and to draw it into <#65727#><#30539#>a-message<#30539#><#65727#> <#71401#>
<#30540#>(d<#30540#><#30541#>efine<#30541#> <#30542#>(echo-message<#30542#> <#30543#>e)<#30543#>
<#30544#>(draw-message<#30544#> <#30545#>a-message<#30545#> <#30546#>(text-contents<#30546#> <#30547#>a-text-field)))<#30547#>
The definition of the call-back function is based on our (domain) knowledge
about the <#65728#><#30551#>gui-item<#30551#><#65728#>s. Specifically, the function
<#65729#><#30552#>echo-message<#30552#><#65729#> obtains the current contents of the <#30553#>text<#30553#> field with
<#65730#><#30554#>text-contents<#30554#><#65730#> as a string, and it draws this string into the
<#30555#>message<#30555#> field with the <#65731#><#30556#>draw-message<#30556#><#65731#> function. To put everything
together, we create a window with two rows:
<#30561#>(<#30561#><#30562#>create-window<#30562#>
<#30563#>(list<#30563#> <#30564#>(list<#30564#> <#30565#>a-text-field<#30565#> <#30566#>a-message)<#30566#>
<#30567#>(list<#30567#> <#30568#>(make-button<#30568#> <#30569#>``Copy<#30569#> <#30570#>Now''<#30570#> <#30571#>echo-message))))<#30571#>
The first row contains the <#30575#>text<#30575#> and the <#30576#>message<#30576#> field; the second one
contains a button with the label <#65732#><#30577#>``Copy<#30577#>\ <#30578#>Now''<#30578#><#65732#> whose call-back
function is <#65733#><#30579#>echo-message<#30579#><#65733#>. The user can now enter text into the
<#30580#>text<#30580#> field, click the button, and see the text appear in the <#30581#>message<#30581#>
field of the window.
The purpose of the third and last example is to create a window with a
choice menu, a message field, and a button. Clicking the button puts the
current choice into the message field. As before, we start by defining the
input and output <#65734#><#30582#>gui-item<#30582#><#65734#>s:
<#30587#>(d<#30587#><#30588#>efine<#30588#> <#30589#>THE-CHOICES<#30589#>
<#30590#>(list<#30590#> <#30591#>``green''<#30591#> <#30592#>``red''<#30592#> <#30593#>``yellow''))<#30593#>
<#30594#>(d<#30594#><#30595#>efine<#30595#> <#30596#>a-choice<#30596#>
<#30597#>(make-choice<#30597#> <#30598#>THE-CHOICES))<#30598#>
<#30599#>(d<#30599#><#30600#>efine<#30600#> <#30601#>a-message<#30601#>
<#30602#>(make-message<#30602#> <#30603#>(first<#30603#> <#30604#>THE-CHOICES)))<#30604#>
Because the list of choices is used more than once in the program, it is
specified in a separate variable definition.
As before, the call-back function for the button interacts with
<#65735#><#30608#>a-choice<#30608#><#65735#> and <#65736#><#30609#>a-message<#30609#><#65736#>:
<#71402#>;; <#65737#><#30614#>echo-choice<#30614#> <#30615#>:<#30615#> <#30616#>X<#30616#> <#30617#><#30617#><#30618#>-;SPMgt;<#30618#><#30619#><#30619#> <#30620#>true<#30620#><#65737#><#71402#>
<#71403#>;; to determine the current choice of <#65738#><#30621#>a-choice<#30621#><#65738#> and<#71403#>
<#71404#>;; to draw the corresponding string into <#65739#><#30622#>a-message<#30622#><#65739#> <#71404#>
<#30623#>(d<#30623#><#30624#>efine<#30624#> <#30625#>(echo-choice<#30625#> <#30626#>e)<#30626#>
<#30627#>(draw-message<#30627#> <#30628#>a-message<#30628#>
<#30629#>(list-ref<#30629#> <#30630#>THE-CHOICES<#30630#>
<#30631#>(choice-index<#30631#> <#30632#>a-choice))))<#30632#>
Specifically, the call-back functionq determines the <#65740#><#30636#>0<#30636#><#65740#>-based index
of the user's current choice with <#65741#><#30637#>choice-index<#30637#><#65741#>, uses Scheme's
<#65742#><#30638#>list-ref<#30638#><#65742#> function to extract the corresponding <#30639#>string<#30639#> from
<#65743#><#30640#>THE-CHOICES<#30640#><#65743#>, and then draws the result into the message field of
the window. To create the window, we arrange <#65744#><#30641#>a-choice<#30641#><#65744#> and
<#65745#><#30642#>a-message<#30642#><#65745#> in one row and the button in a row below:
<#30647#>(<#30647#><#30648#>create-window<#30648#>
<#30649#>(list<#30649#> <#30650#>(list<#30650#> <#30651#>a-choice<#30651#> <#30652#>a-message)<#30652#>
<#30653#>(list<#30653#> <#30654#>(make-button<#30654#> <#30655#>``Confirm<#30655#> <#30656#>Choice''<#30656#> <#30657#>echo-choice))))<#30657#>
<#65746#>;; <#30665#>Model<#30665#>:<#65746#>
<#71405#>;; <#65747#><#30666#>build-number<#30666#> <#30667#>:<#30667#> <#30668#>(listof<#30668#> <#30669#>digit)<#30669#> <#30670#><#30670#><#30671#>-;SPMgt;<#30671#><#30672#><#30672#> <#30673#>number<#30673#><#65747#><#71405#>
<#30674#>;; to translate a list of digits into a number<#30674#>
<#71406#>;; example: <#65748#><#30675#>(build-number<#30675#> <#30676#>(list<#30676#> <#30677#>1<#30677#> <#30678#>2<#30678#> <#30679#>3))<#30679#> <#30680#>=<#30680#> <#30681#>123<#30681#><#65748#><#71406#>
<#30682#>(define<#30682#> <#30683#>(build-number<#30683#> <#30684#>x)<#30684#> <#30685#>...)<#30685#>
<#65749#>;; <#65749#>
<#65750#>;; <#30688#>View<#30688#>:<#65750#>
<#30689#>;; the ten digits as strings <#30689#>
<#30690#>(d<#30690#><#30691#>efine<#30691#> <#30692#>DIGITS<#30692#>
<#30693#>(build-list<#30693#> <#30694#>10<#30694#> <#71407#><#65751#><#30695#>number<#30695#><#65751#><#65752#><#30696#><#30696#><#30697#>-;SPMgt;<#30697#><#30698#><#30698#><#65752#><#65753#><#30699#>string<#30699#><#65753#><#71407#><#30700#>))<#30700#>
<#30701#>;; a list of three digit choice menus <#30701#>
<#30702#>(d<#30702#><#30703#>efine<#30703#> <#30704#>digit-choosers<#30704#>
<#30705#>(build-list<#30705#> <#30706#>3<#30706#> <#30707#>(lambda<#30707#> <#30708#>(i)<#30708#> <#30709#>(make-choice<#30709#> <#30710#>DIGITS))))<#30710#>
<#65754#>;; a <#30711#>message<#30711#> field for saying hello and displaying the number <#65754#>
<#30712#>(d<#30712#><#30713#>efine<#30713#> <#30714#>a-msg<#30714#>
<#30715#>(make-message<#30715#> <#30716#>``Welcome''))<#30716#>
<#65755#>;; <#65755#>
<#65756#>;; <#30719#>Controller<#30719#>: <#65756#>
<#71408#>;; <#65757#><#30720#>check-call-back<#30720#> <#30721#>:<#30721#> <#30722#>X<#30722#> <#30723#><#30723#><#30724#>-;SPMgt;<#30724#><#30725#><#30725#> <#30726#>true<#30726#><#65757#><#71408#>
<#30727#>;; to get the current choices of digits, convert them to a number, <#30727#>
<#65758#>;; and to draw this number as a string into the <#30728#>message<#30728#> field <#65758#>
<#30729#>(d<#30729#><#30730#>efine<#30730#> <#30731#>(check-call-back<#30731#> <#30732#>b)<#30732#>
<#30733#>(draw-message<#30733#> <#30734#>a-msg<#30734#>
<#30735#>(<#30735#><#71409#><#65759#><#30736#>number<#30736#><#65759#><#65760#><#30737#><#30737#><#30738#>-;SPMgt;<#30738#><#30739#><#30739#><#65760#><#65761#><#30740#>string<#30740#><#65761#><#71409#>
<#30741#>(<#30741#><#30742#>build-number<#30742#>
<#30743#>(map<#30743#> <#30744#>choice-index<#30744#> <#30745#>digit-choosers)))))<#30745#>
<#30746#>(<#30746#><#30747#>create-window<#30747#>
<#30748#>(<#30748#><#30749#>list<#30749#>
<#30750#>(append<#30750#> <#30751#>digit-choosers<#30751#> <#30752#>(list<#30752#> <#30753#>a-msg))<#30753#>
<#30754#>(list<#30754#> <#30755#>(make-button<#30755#> <#30756#>``Check<#30756#> <#30757#>Guess''<#30757#> <#30758#>check-call-back))))<#30758#>
<#30762#>Figure: A GUI for echoing digits as numbers<#30762#>
Now that we have examined some basic GUI programs, we can study a program
with full-fledged core and GUI components. Take a look at the definitions
in figure~#figcopymany#30764>
The control component of a program is also responsible for the visual
composition of the window. The teachpack provides only one function for
this purpose: <#65765#><#30770#>create-window<#30770#><#65765#>. Standard GUI toolboxes provide many
more functions, though all of these toolboxes differ from each other and
are changing rapidly.
<#30773#>Exercise 22.3.1<#30773#>
<#30815#>(<#30815#><#65778#><#30816#>string<#30816#><#65778#><#65779#><#30817#><#30817#><#30818#>-;SPMgt;<#30818#><#30819#><#30819#><#65779#><#65780#><#30820#>number<#30820#><#65780#> <#30821#>``6670004'')<#30821#>
<#30822#>=<#30822#> <#30823#>6670004<#30823#>
<#30831#>(<#30831#><#65781#><#30832#>string<#30832#><#65781#><#65782#><#30833#><#30833#><#30834#>-;SPMgt;<#30834#><#30835#><#30835#><#65782#><#65783#><#30836#>number<#30836#><#65783#> <#30837#>``667-0004'')<#30837#>
<#30838#>=<#30838#> <#30839#>false<#30839#>
The generalization demonstrates how one and the same GUI can use two
distinct models.~ Solution<#65784#><#65784#>
<#30848#>Exercise 22.3.3<#30848#>
A <#65792#><#30860#>gui-table<#30860#><#65792#> is a <#65793#><#30861#>(listof<#30861#>\ <#30862#>(listof<#30862#>\ <#30863#>cell))<#30863#><#65793#> .
A <#65794#><#30866#>cell<#30866#><#65794#> is either
Here are two examples:
<#30874#>(d<#30874#><#30875#>efine<#30875#> <#30876#>pad<#30876#>
<#30877#>'<#30877#><#30878#>(<#30878#><#30879#>(1<#30879#> <#30880#>2<#30880#> <#30881#>3)<#30881#>
<#30882#>(4<#30882#> <#30883#>5<#30883#> <#30884#>6)<#30884#>
<#30885#>(7<#30885#> <#30886#>8<#30886#> <#30887#>9)<#30887#>
<#30888#>(\<#30888#><#30889#>#<#30889#> <#30890#>0<#30890#> <#30891#>*)))<#30891#>
<#30898#>(d<#30898#><#30899#>efine<#30899#> <#30900#>pad2<#30900#>
<#30901#>'<#30901#><#30902#>(<#30902#><#30903#>(1<#30903#> <#30904#>2<#30904#> <#30905#>3<#30905#> <#30906#>+)<#30906#>
<#30907#>(4<#30907#> <#30908#>5<#30908#> <#30909#>6<#30909#> <#30910#>-)<#30910#>
<#30911#>(7<#30911#> <#30912#>8<#30912#> <#30913#>9<#30913#> <#30914#>*)<#30914#>
<#30915#>(0<#30915#> <#30916#>=<#30916#> <#30917#>\<#30917#><#30918#>.<#30918#> <#30919#>/)))<#30919#>
The table on the left lays out a virtual phone pad, the right one a
calculator pad.
The function <#71413#><#65795#><#30923#>pad<#30923#><#65795#><#65796#><#30924#><#30924#><#30925#>-;SPMgt;<#30925#><#30926#><#30926#><#65796#><#65797#><#30927#>gui<#30927#><#65797#><#71413#> should turn each cell into a button. The
resulting list should be prefixed with two messages. The first one displays
the title and never changes. The second one displays the latest button that
the user clicked. The two examples above should produce the following two
GUIs: