Previous Up Next

Chapter 4  Zoggy

4.1  Introduction

Zoggy is a graphical interface builder for LablGtk, the OCaml/GTK library. Zoogy allows you to graphically build your windows and boxes, then generate OCaml code which creates these windows and boxes.

We explain the use of Zoggy as in a tutorial, through two examples. The ``Hello world'' example presented in section 4.3 is a simple first example of the use of Zoggy. A more complex example is presented in section 4.4.

4.2  The templates file

When Zoggy is launched, it loads the ~/.zoggy/templates file. This file is a regular Zoggy file which can be edited with Zoggy. Each entity in this file then appears in the Template menu of the entity edition window. Selectionning a template insert it in the current entity. So you can define your templates by editing your ~/.zoggy/templates file, then use these templates when you use Zoggy to edit other files.

4.3  The ``Hello world'' example

This example is a simple window with a button and a label. Clicking on the button will display the text ``Hello world'' in the label. The final window is displayed on figure 4.3.


Figure 4.1: The ``Hello world'' example window


The development process consists of the following steps:
  1. Describing the window with Zoggy,
  2. Generating code from the window description,
  3. Adding code which uses the generated code,
  4. Compiling and executing.

4.3.1  Describing the window

We will describe the window in the file guibase.zog. This is done by the following command:
zoggy guibase.zog
The window of figure 4.3.1 appears. This window is used to define entities. Each entity will become a class in the generated code. The entity parameters will become class parameters. For each entity, a hierarchy of widgets is defined, as explained later. Each new instance of a class will build the widgets described in the entity from which the class was generated.


Figure 4.2: The Zoggy main window


We need to add a new entity, corresponding to the window we want to build. The Entity/Add entity command pops up a window where the entity name can be given. We'll call it hello. After a click on the ``Ok'' button, the main window now contains the new entity.

Click on the hello entity in the main window to open it. The entity window appears, in which we can edit the widgets of the entity. It is composed of For the moment, the widget hierarchy is empty, so the first thing to do is to create a window: click on the ``window'' button in the palette. Since buttons are ordered in the widget alphabetical order (top to bottom and left to right), this button is at the end.

Two things occur: Now click on the new item in the tree to edit the properties of the window. The ``Name'' field contains the OCaml identificator which will be used for the widget in the code of the generated class. If it starts with a '_', then this widget will not appear in the class interface (but it will still be built for each new instance of the class). Rename this widget to win.

Under the ``Name'' field, the properties of the window appear. For each property, its name, its value, and the OCaml type of its value are displayed.

The value can be changed, but in the end, it must be valid OCaml code of the correct OCaml type.

For properties with integer values, -1 means ``no value'' (or ``default value'').

Some properties have values of a variant type. In this case, a value among the possible ones can be selected in the associated combo widget, but OCaml code can still be used instead, to compute the value at execution. In such a case, the preview will no be relevant for this property, since the value will only be known at execution.

Here we will change the title of our window : set the ``title'' value to ``Hello world''. Note that the double quotes are important since this must be correct OCaml code of type string.

You can see the preview window change as you modify the value.

Now we must add a vbox in our window, which will contain one label and one button. Click on the ``vbox'' button in the palette, select it in the tree and rename it to vbox. Then click on the ``label'' button in the palette to add our label widget. Select it in the tree, rename it to wlabel, and set the ``text'' property to ``Nothing yet''.

As you added the widgets and changed properties of the label, you may have noticed that the size of the window changed too. That's because it adjusts itself to the widget it contains. When we set the text of the label widget, this widget needed mode space, so its parent widget (the vbox) needed more space and the window grew. This behaviour can be changed with the properties ``allow_shrink'', ``allow_grow'' and ``auto_grow'' of the window.

Now we must add a button to the vbox. Select the vbox item in the widget tree, and click on the ``button'' button in the palette. A menu appears, click on ``with label'' to create a button with already a label in it. Enter ``Say it'' in the window asking you the label text. As you can see in the widget tree, two more widgets have been created, a button and a label in it. The label has a name beginning with '_', to indicate that it won't be in the interface of the generated class. Since we'll need to access the button to specify what must be done when it is clicked, select the button and rename it to wbutton.

Now you can save your description with the File/Save command, and quit Zoggy.

4.3.2  Generating code

The command
camlp4o pa_zog.cma pr_o.cmo -impl guibase.zog > guibase.ml
will generate code to guibase.ml, according to the entities found in guibase.zog.

Let's have a look at the generated code. Our ``hello'' entity becomes the hello class:
class hello () =
The () parameter is important since without it (and no other parameter) the widgets would be created only once, even with various instances of the class.

Now we can see the creation of the widgets defined in the entity:
  let win =
    GWindow.window ~title:"Hello world" ~allow_shrink:true ~allow_grow:true
      ~auto_shrink:true ~modal:true ()
  in
  let vbox = GPack.vbox ~homogeneous:false ~packing:win#add () in
  let wlabel =
    GMisc.label ~text:"Nothing yet" ~justify:`LEFT ~line_wrap:true ~xpad:2
      ~ypad:2 ~packing:(vbox#pack ~expand:false ~fill:true) ()
  in
  let wbutton =
    GButton.button ~packing:(vbox#pack ~expand:false ~fill:true) ()
  in
  let _5 =
    GMisc.label ~text:"Say it" ~justify:`LEFT ~line_wrap:true
      ~packing:wbutton#add ()
  in
We can find the OCaml code we typed, in some of the properties.

At last, the object is defined as :
  object
    val win = win
    val vbox = vbox
    val wlabel = wlabel
    val wbutton = wbutton
    method win = win
    method vbox = vbox
    method wlabel = wlabel
    method wbutton = wbutton
  end;;
As you can see, the class can be used in two ways: In the next step, we will use the first way to use this generated class.

4.3.3  Using the generated code

Now create a file hello.ml with the following code:
(* Gtk initializations *)
let _ = GMain.Main.init ()

class gui ()=
  object
    inherit Guibase.hello ()
      
    initializer
      (* Exit the event loop when the window is destroyed *)
      ignore (win#connect#destroy GMain.Main.quit);

      (* Display "Hello world" when the button is clicked. *)
      ignore (wbutton#connect#clicked 
  (fun () -> wlabel#set_text "Hello world"));

      (* Show the window *)
      win#show ()
  end

(* Build the window *)
let c = new gui ()

(* Enter event loop *)
let _ = GMain.Main.main ()

4.3.4  Compiling and executing

Now compile with the following command:
ocamlc -o hello -I +lablgtk lablgtk.cma guibase.ml hello.ml
and execute :
./hello

Note that you can compile directly guibase.zog to guibase.cmo and guibase.cmi with the following command:
ocamlc -c -pp "camlp4o pa_zog.cma -impl" -I +lablgtk -impl guibase.zog

Try adding other widgets and changing properties in this first example...

4.4  Example 2

Yet to come.


Previous Up Next