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:
-
Describing the window with Zoggy,
- Generating code from the window description,
- Adding code which uses the generated code,
- 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
-
a menu bar, with common actions like save, copy, paste, ...
and some others we don't care about for the moment.
- a frame on the left, which will contain the properties of
the selected widget,
- a tree widget in the middle, showing the hierarchy of the widgets
of the entity,
- a palette on the right, containing buttons. These buttons can be
used to add widgets to the entity widgets hierarchy.
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:
-
a new empty window appears, it is the preview window. When you add
widgets to the widgets hierarchy, they will be displayed in this window,
and you will see them change when you change their properties.
This preview window can be hidden or shown by switching the ``preview''
check button in the entity window.
- a node appears in the tree of the entity window.
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:
-
by inheriting from this class, you can access the widget
directly by typing for example:
win#show ()
- by making a new instance of the class and then accessing
the widgets through the methods, like in :
let c = new hello () in c#win#show ()
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.