1.3 QHTML Tutorial

The example given in this chapter describes how a user interface is built using the QHTML module. The creation of the widgets, their geometry inside the window and their interaction with Mozart are described.


Figure 1.2.


1.3.1 Geometry management

The example application will consist of a window composed by

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 upon window resizing. 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 :

The toolbar is composed of button widgets and a file selection widget. The value parameter defines the text of the button.

The toolbar is described by :

Toolbar=lr(button(value:"Save")
           button(value:"Load")
           file
           button(value:"Quit"))

which literally means : place these four widgets buttons respectively from left to right, each widget taking the size it needs to display itself. Combining with the textarea widget, we obtain :

Desc=toplevel(td(Toolbar
                 textarea))

which literally means : inside the main window (toplevel widget), place the toolbar and the textarea 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={QHTML.build Desc}

This window is not displayed inside any Internet Browser by default. To open a new IE window and display the QHTML components inside it, execute :

{Window show}


Figure 1.3.


The result so far is not very good : widgets have a fixed size upon window resizing and don't fit as wanted.

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:nwe
           button(value:"Save" glue:w)
           button(value:"Load" glue:w)
           file(glue:w)
           button(value:"Quit" glue:e))

and also

Desc=toplevel(td(glue:nswe
                 Toolbar
                 textarea(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.

1.3.2 Interaction with the user

An action can be associated to buttons. It is executed when the user clicks the button :

button(value:"Click" action:OzProcedure)

We can define procedures for the three buttons of the application. The Load and Save procedures will take the name selected in the file widget and load it into the textarea widget or save its content.

We need a way to dynamically get the state of the file widget to get the selected name, and a way to change or get the contents of the textarea widget. This can be achieved by using handle parameters : when the window is built, variables specified as handle parameters are bound to Oz objects controlling the corresponding widget. The modified code now looks like :

FH % FileHandler
TAH % TextAreaHandler
 
Toolbar=lr(glue:nwe
           button(value:"Save" glue:w action:Save)
           button(value:"Load" glue:w action:Load)
           file(glue:w handle:FH)
           button(value:"Quit" glue:e action:Quit))
 
Desc=toplevel(td(glue:nswe
                 Toolbar
                 textarea(glue:nswe handle:TAH)))

When the window is built, the contents of the textarea widget can be obtained by :

{TAH get(value:$)}

and set by :

{TAH set($)}

The selected file in the file widget can be obtained by :

{FH get($)}

Here are the definitions of the three procedures defined as action by the buttons :

proc{Save}
   try 
      File={New Open.file init(name:{FH get(value:$)}
                               flags:[write create truncate])}
      {File write(vs:{TAH get(value:$)})}
   in 
      {File close}
      {Window alert("File successfully saved.")}
   catch _ then 
      {Window alert("Unable to save file.")}
   end    
end 
 
proc{Load}
   try 
      File={New Open.file init(name:{FH get(value:$)})}
      Data={File read(list:$ size:all)}
      {File close}
   in 
      {TAH set(value:Data)}
   catch _ then 
      {Window alert("Unable to load file. Check if specified file exists.")}
   end 
end 
 
proc{Quit}
   {Window close}
end

The application is now complete ! Here is the full code.


Donatien Grolaux
Version 1.3.0 (20010902)