<< Prev | - Up - | Next >> |
The example given in this chapter describes how a gui is built using QTk module. The creation of the widgets, their geometry inside the window and their interaction with Mozart are described.
The example application will consist of a window composed by
A toolbar with the following buttons : Save, Load and Quit.
A main area where the user can type the text.
The construction of a window is completely described by a record. This record defines the widgets that compose the window, how these widgets must be placed and what is their behaviour is they must be resized. The label of the record defines the widget that must be placed. The content of the record defines the parameters of the widget. Some widgets act as containers for other widgets. The two main containers are :
td
: all widgets contained in this one are placed top to down
lr
: all widgets contained in this one are placed left to right
The toolbar wil be composed of button
widgets. The text
parameter defines the text of the button.
The toolbar is described by :
Toolbar=lr(button(text:"Save")
button(text:"Load")
button(text:"Quit"))
which literally means : place these three buttons respectively from left to right, each button taking the size it needs to display itself. Combining with the text widget, we obtain :
Description=td(Toolbar
text)
which literally means : place the toolbar and the text respectively from top to bottom, each widget taking the size it needs to display itself.
Now we can build a window from this description by the command :
Window={QTk.build Description}
This window is hidden by default, so you have to show it to make it visible :
{Window show}
If you resize the window, the widgets don't resize in a very clever way inside the window.
One expects the toolbar to stick itself to the top left of the window, and the text widget to take all remaining available size below. All widgets have a glue parameter that allow to specify contraints to the geometry manager. Valid values for the glue parameters are atoms that are combinations of n
, s
, w
and e
. By default a widget takes as much place as it needs to draw itself, and if the area in which it is drawed is bigger than that size, the widget is centered inside. By specifying n
(resp s
, w
, e
) you enforce the north (resp south, west and east) border of the widget to glue to its top (resp down, left, right) neighboor. If you specify both ns
(resp we
) you enforce both opposite border to stick to their respective neighboor, resulting in the widget taking all the vertical (resp horizontal) space available.
Using the glue parameter we define :
Toolbar=lr(glue:we % the toolbar glues itself to the top left of the window
button(text:"Save" glue:w) % the button glues itself to the left of the lr widget
button(text:"Load" glue:w) % idem
button(text:"Quit" glue:w)) % idem
and also
Description=td(Toolbar
text(glue:nswe))
Note that the very first td
or lr
widget is always implicitely glue:nswe
. Rebuilding and showing the window, we obtain an application that has a complete graphical user interface, except that it is an empty shell.
An action can be associated to buttons. It is executed when the user clicks the button :
button(text:"Quit" glue:w action:proc{$} {Application.exit 0})}
This definition makes the oz application terminate when the user clicks the Quit button. Another parameter for closes the window :
button(text:"Quit" glue:w action:toplevel#close)
Let's make procedures for the Save and Load buttons. The new definitions for these buttons are thus :
button(text:"Save" glue:w action:SaveText)
button(text:"Load" glue:w action:LoadText)
The LoadText
and SaveText
procedures will do these things :
Ask a filename. Standard dialog boxes are provided in QTk : {QTk.dialogbox load(...)}
and {QTk.dialogbox save(...)}
Get the contents of the text widget and save it to the file or get the contents of the file and change the contents of the text widget accordingly.
We need a way to dynamically change or get its state, i.e. interact with the widget. This can be done with an handle :
TextHandle
Description=td(Toolbar
text(glue:nswe handle:TextHandle))
After the window is built, the unbound variable TextHandle is bound to an object that controls the text widget. The current text can be obtained by :
{TextHandle get($)}
and set by :
{TextHandle set($)}
We can now give the SaveText
and LoadText
procedures :
proc{SaveText}
Name={QTk.dialogbox save($)}
in
try
File={New Open.file init(name:Name flags:[write create])}
Contents={TextHandle get($)}
in
{File write(vs:Contents)}
{File close}
catch _ then skip end
end
proc{LoadText}
Name={QTk.dialogbox load($)}
Contents={TextHandle get($)}
in
try
File={New Open.file init(name:Name)}
Contents={File read(list:$ size:all)}
in
{TextHandle set(Contents)}
{File close}
catch _ then skip end
end
And the application is now complete.
Instead of using standard buttons, we might want to use a toolbar look and feel. A QTk widget does that : tbbutton
. As its interface is the same as standard buttons, we just have to change le label of the record :
Toolbar=lr(glue:we
tbbutton(text:"Save" glue:w)
tbbutton(text:"Load" glue:w)
tbbutton(text:"Quit" glue:w))
If there is a lot of text, scrollbars are usefull to allow easy mouse navigation. This can be added with a parameter :
text(glue:nswe handle:TextHandle tdscrollbar:true)
Moreover one may prefer the white color as background color for the text :
text(glue:nswe handle:TextHandle tdscrollbar:true bg:white)
As you can see, widgets are highly configurable by parameters. Most of these parameters can be dynamically changed :
{TextHandle set(bg:white)}
Sets also the background to white but it can be done at any time as soon as the window is built and as long as it isn't closed. Interfaces to widgets were made as uniform as possible and similar widgets have similar parameters name and use.
declare
[QTk]={Module.link ["http://www.info.ucl.ac.be/people/ned/qtk/QTk.ozf"]}
proc{SaveText}
Name={QTk.dialogbox save($)}
in
try
File={New Open.file init(name:Name flags:[write create])}
Contents={TextHandle get($)}
in
{File write(vs:Contents)}
{File close}
catch _ then skip end
end
proc{LoadText}
Name={QTk.dialogbox load($)}
in
try
File={New Open.file init(name:Name)}
Contents={File read(list:$ size:all)}
in
{TextHandle set(Contents)}
{File close}
catch _ then skip end
end
Toolbar=lr(glue:we
tbbutton(text:"Save" glue:w action:SaveText)
tbbutton(text:"Load" glue:w action:LoadText)
tbbutton(text:"Quit" glue:w action:toplevel#close))
TextHandle
Window={QTk.build td(Toolbar
text(glue:nswe handle:TextHandle bg:white tdscrollbar:true))}
{Window show}
<< Prev | - Up - | Next >> |