Layout management

In this chapter we will show how to lay out our widgets in windows or dialogs.

When we design the GUI of our application, we decide what widgets we will use and how we will organise those widgets in the application. To organise our widgets, we use specialised non visible widgets called layout containers. In this chapter, we will mention Alignment, Fixed, VBox and Table.

Fixed

The Fixed container places child widgets at fixed positions and with fixed sizes. This container performs no automatic layout management. In most applications, we do not use this container. There are some specialised areas, where we use it. For example games, specialised applications that work with diagrams, resizable components that can be moved (like a chart in a spreadsheet application), small educational examples.

#!/usr/bin/seed

/*
ZetCode JavaScript GTK tutorial

In this program, we lay out widgets
using absolute positioning

author: Jan Bodnar
website: www.zetcode.com
last modified: July 2011
*/

Gtk = imports.gi.Gtk;
Gdk = imports.gi.Gdk;


Gtk.init(null, null);

Example = new GType({
    parent: Gtk.Window.type,
    name: "Example",
    init: function ()
    {

        init_ui(this);
        
        function init_ui(w) {
          
            w.signal.hide.connect(Gtk.main_quit);
            w.set_default_size(300, 280);
            w.set_title("Fixed");
            w.set_position(Gtk.WindowPosition.CENTER);

            w.modify_bg(Gtk.StateType.NORMAL, 
                new Gdk.Color({red:6400, green:6400, blue:6440}));
            
            var image1 = new Gtk.Image.from_file("bardejov.jpg");
            var image2 = new Gtk.Image.from_file("rotunda.jpg");
            var image3 = new Gtk.Image.from_file("mincol.jpg");

            var fixed = new Gtk.Fixed();
            
            fixed.put(image1, 20, 20);
            fixed.put(image2, 40, 160);
            fixed.put(image3, 170, 50);
            
            w.add(fixed);
            w.show_all();                     
        }
    }       
});


var window = new Example();
Gtk.main();

In our example, we show three small images on the window. We explicitly specify the x, y coordinates, where we place these images.

w.modify_bg(Gtk.StateType.NORMAL, 
    new Gdk.Color({red:6400, green:6400, blue:6440}));

For better visual experience, we change the background colour to dark gray.

var image1 = new Gtk.Image.from_file("bardejov.jpg");

The Image is a widget that is used to display images. The picture is loaded from the file on the disk.

var fixed = new Gtk.Fixed();

We create the Fixed container.

fixed.put(image1, 20, 20);

We place the first image at x=20, y=20 coordinates.

w.add(fixed);

Finally, we add the Fixed container to the Window.

Fixed
Figure: Fixed

Buttons

In this code example, we will use a vertical box, a horizontal box and an alignment widget. A horizontal box arranges widgets in a single row. Similarly, a vertical box places its widgets in one column. The Alignment container controls the alignment and the size of its child widget.

#!/usr/bin/seed

/*
ZetCode JavaScript GTK tutorial

In this program, we position two buttons
in the bottom right corner of the window.
We use horizontal and vertical boxes.

author: Jan Bodnar
website: www.zetcode.com
last modified: July 2011
*/

Gtk = imports.gi.Gtk;

Gtk.init(null, null);

Example = new GType({
    parent: Gtk.Window.type,
    name: "Example",
    init: function ()
    {
        
        init_ui(this);
        
        function init_ui(w) {
      
            w.signal.hide.connect(Gtk.main_quit);
            w.set_default_size(260, 150);
            w.set_title("Buttons");
            w.set_position(Gtk.WindowPosition.CENTER);

            var vbox = new Gtk.VBox({homogeneous: false, spacing:5});
            var hbox = new Gtk.HBox({homogeneous: true, spacing:3});

            var space = new Gtk.Frame();
            vbox.pack_start(space, true, true, 0);
            
            var okButton = new Gtk.Button({label:"OK"});
            okButton.set_size_request(70, 30);
            var closeButton = new Gtk.Button({label:"Close"});
            
            hbox.add(okButton);
            hbox.add(closeButton);
            
            var halign = new Gtk.Alignment({xalign: 1.0, yalign: 0.0, 
                                           xscale: 0.0, yscale: 0.0});
            halign.add(hbox);
            vbox.pack_start(halign, false, false, 3);

            w.add(vbox);
            w.show_all(); 
        }
    }       
});


var window = new Example();
Gtk.main();

In the code example, we place two buttons into the right bottom corner of the window. To accomplish this, we use one horizontal box and one vertical box and one alignment container.

var vbox = new Gtk.VBox({homogeneous: false, spacing:5});

A vertical box container is created. We set the homogeneous member to false. This means that widgets put into the vertical box will hot have the same size. The vertical spacing between widgets is set to 5 pixels.

var space = new Gtk.Frame();

Here we create a Frame widget. The purpose of this widget is to take up space above the two buttons.

vbox.pack_start(space, true, true, 0);

Here we place the frame widget into the vertical box. The first parameter of the method is the widget, which is being placed into the box. The following three parameters are expand, fill and padding. The expand parameter is set to true, which means that free space will be allocated around the widget. When the fill parameter is set to true, the widget actually takes up all the free space around it. There is no padding around the child widget.

var hbox = new Gtk.HBox({homogeneous: true, spacing:3});            

This code line creates a horizontal box. All widgets inside the box will have the same size. There will be 3px space between the widgets horizontally.

var okButton = new Gtk.Button({label:"OK"});
okButton.set_size_request(70, 30);
var closeButton = new Gtk.Button({label:"Close"});

hbox.add(okButton);
hbox.add(closeButton);

We create two buttons and put them inside the horizontal box.

var halign = new Gtk.Alignment({xalign: 1.0, yalign: 0.0, 
                                xscale: 0.0, yscale: 0.0});
halign.add(hbox);
vbox.pack_start(halign, false, false, 3);

This will create an alignment container that will place its child widget to the right. The xalign member set to 1.0 will put all free space to the left of the horizontal box. This will push the two buttons to the right. We add the horizontal box into the alignment container and pack the alignment container into the vertical box. We must keep in mind that the alignment container takes only one child widget. That's why we must use the horizontal box.

Buttons
Figure: Buttons

Calculator skeleton

The Table widget arranges widgets in rows and columns.

#!/usr/bin/seed

/*
ZetCode JavaScript GTK tutorial

In this program we create a skeleton of
a calculator. We use the Table widget.

author: Jan Bodnar
website: www.zetcode.com
last modified: July 2011
*/

Gtk = imports.gi.Gtk;
Gdk = imports.gi.Gdk;

Gtk.init(null, null);

Example = new GType({
    parent: Gtk.Window.type,
    name: "Example",
    init: function ()
    {

        init_ui(this);
      
        function init_ui(w) {  
      
            w.signal.hide.connect(Gtk.main_quit);
            w.set_default_size(300, 250);
            w.set_title("Calculator");
            w.set_position(Gtk.WindowPosition.CENTER);

            var vbox = new Gtk.VBox({homogeneous: false, spacing:2});
            
            var mb = new Gtk.MenuBar();
            var filemenu = new Gtk.Menu();
            var file = new Gtk.MenuItem({label:"File"});
            file.set_submenu(filemenu);
            mb.append(file);

            vbox.pack_start(mb, false, false, 0);

            var table = new Gtk.Table.c_new(5, 4, true);
            
            table.attach_defaults(new Gtk.Button.with_label("Cls"), 0, 1, 0, 1);
            table.attach_defaults(new Gtk.Button.with_label("Bck"), 1, 2, 0, 1);
            table.attach_defaults(new Gtk.Label(), 2, 3, 0, 1);
            table.attach_defaults(new Gtk.Button.with_label("Close"), 3, 4, 0, 1);

            table.attach_defaults(new Gtk.Button.with_label("7"), 0, 1, 1, 2);
            table.attach_defaults(new Gtk.Button.with_label("8"), 1, 2, 1, 2);
            table.attach_defaults(new Gtk.Button.with_label("9"), 2, 3, 1, 2);
            table.attach_defaults(new Gtk.Button.with_label("/"), 3, 4, 1, 2);

            table.attach_defaults(new Gtk.Button.with_label("4"), 0, 1, 2, 3);
            table.attach_defaults(new Gtk.Button.with_label("5"), 1, 2, 2, 3);
            table.attach_defaults(new Gtk.Button.with_label("6"), 2, 3, 2, 3);
            table.attach_defaults(new Gtk.Button.with_label("*"), 3, 4, 2, 3);

            table.attach_defaults(new Gtk.Button.with_label("1"), 0, 1, 3, 4);
            table.attach_defaults(new Gtk.Button.with_label("2"), 1, 2, 3, 4);
            table.attach_defaults(new Gtk.Button.with_label("3"), 2, 3, 3, 4);
            table.attach_defaults(new Gtk.Button.with_label("-"), 3, 4, 3, 4);

            table.attach_defaults(new Gtk.Button.with_label("0"), 0, 1, 4, 5);
            table.attach_defaults(new Gtk.Button.with_label("."), 1, 2, 4, 5);
            table.attach_defaults(new Gtk.Button.with_label("="), 2, 3, 4, 5);
            table.attach_defaults(new Gtk.Button.with_label("+"), 3, 4, 4, 5);

            vbox.pack_start(new Gtk.Entry(), false, false, 0);            
            vbox.pack_end(table, true, true, 0);            
            
            w.add(vbox);
            w.show_all(); 
        }
    }   
    
});

var window = new Example();
Gtk.main();

We use the Table widget to create a calculator skeleton.

var table = new Gtk.Table.c_new(5, 4, true);

We create a table widget with 5 rows and 4 columns. The third parameter is the homogenous parameter. If set to true, all the widgets in the table are of the same size. The size of all widgets is equal to the largest widget in the table container.

table.attach_defaults(new Gtk.Button.with_label("Cls"), 0, 1, 0, 1);

We attach a button to the table container. To the top-left cell of the table. The first two parameters are the left and right sides of the cell, the last two parameters are the top and left sides of the cell.

vbox.pack_end(table, true, true, 0);

We pack the table widget into the vertical box.

Calculator skeleton
Figure: Calculator skeleton

Windows

Next we will create a more advanced example. We show a window, that can be found in the JDeveloper IDE.

#!/usr/bin/seed

/*
ZetCode JavaScript GTK tutorial

This is a more complicated layout example.
We use Alignment and Table widgets. 

author: Jan Bodnar
website: www.zetcode.com
last modified: July 2011
*/


Gtk = imports.gi.Gtk;
Gdk = imports.gi.Gdk;


Gtk.init(null, null);

Example = new GType({
    parent: Gtk.Window.type,
    name: "Example",
    init: function ()
    {

        init_ui(this);
      
        function init_ui(w) {

            w.signal.hide.connect(Gtk.main_quit);
            w.set_default_size(300, 280);
            w.set_title("Windows");
            w.set_position(Gtk.WindowPosition.CENTER);

            w.set_border_width(15);
            
            var table = new Gtk.Table.c_new(8, 4, false);
            table.set_col_spacings(3);

            var title = new Gtk.Label.c_new("Windows");

            var halign = new Gtk.Alignment.c_new(0.0, 0.0, 0.0, 0.0);
            halign.add(title);
            
            table.attach(halign, 0, 1, 0, 1, Gtk.AttachOptions.FILL,
                Gtk.AttachOptions.FILL, 0, 0);
                
            var frame = new Gtk.Frame();
            table.attach(frame, 0, 2, 1, 3, Gtk.AttachOptions.FILL | 
                Gtk.AttachOptions.EXPAND, Gtk.AttachOptions.FILL | 
                Gtk.AttachOptions.EXPAND, 1, 1);

            var activate = new Gtk.Button.with_label("Activate");
            activate.set_size_request(50, 30);
            table.attach(activate, 3, 4, 1, 2, Gtk.AttachOptions.FILL,
                Gtk.AttachOptions.SHRINK, 1, 1)
            
            var valign = new Gtk.Alignment.c_new(0.0, 0.0, 0.0, 0.0);
            var closeButton = new Gtk.Button.with_label("Close");
            closeButton.set_size_request(70, 30);
            valign.add(closeButton);
            table.set_row_spacing(1, 3);
            table.attach(valign, 3, 4, 2, 3, Gtk.AttachOptions.FILL,
                Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, 1, 1)
                
            halign2 = new Gtk.Alignment.c_new(0.0, 1.0, 0.0, 0.0);
            help = new Gtk.Button.with_label("Help");
            help.set_size_request(70, 30);
            halign2.add(help);
            table.set_row_spacing(3, 6);
            table.attach(halign2, 0, 1, 4, 5, Gtk.AttachOptions.FILL,
                Gtk.AttachOptions.FILL, 0, 0);
            
            var okButton = new Gtk.Button.with_label("OK");
            okButton.set_size_request(70, 30);
            table.attach(okButton, 3, 4, 4, 5, Gtk.AttachOptions.FILL,
                Gtk.AttachOptions.FILL, 0, 0);
                              
            w.add(table);
            w.show_all(); 
        }
    }       
});


var window = new Example();
Gtk.main();

The code example shows, how we can create a similar window in JavaScript GTK.

var table = new Gtk.Table.c_new(8, 4, false);
table.set_col_spacings(3);

The example is based on the Table container. There will be 3px space between columns.

var title = new Gtk.Label.c_new("Windows");

var halign = new Gtk.Alignment.c_new(0.0, 0.0, 0.0, 0.0);
halign.add(title);

table.attach(halign, 0, 1, 0, 1, Gtk.AttachOptions.FILL,
    Gtk.AttachOptions.FILL, 0, 0);

This code creates a label that is aligned to the left. The label is placed in the first row of the first column of the Table container.

var frame = new Gtk.Frame();
table.attach(frame, 0, 2, 1, 3, Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND,
    Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, 1, 1);

The frame widget spans two rows and two columns. It will consume all free space around it. Thus, taking the bulk of the area of the window.

var valign = new Gtk.Alignment.c_new(0.0, 0.0, 0.0, 0.0);
var closeButton = new Gtk.Button.with_label("Close");
closeButton.set_size_request(70, 30);
valign.add(closeButton);
table.set_row_spacing(1, 3);
table.attach(valign, 3, 4, 2, 3, Gtk.AttachOptions.FILL,
    Gtk.AttachOptions.FILL | Gtk.AttachOptions.EXPAND, 1, 1)

We put the close button next to the frame widget into the fourth column. (we count from zero) We add the button into the alignment widget, so that we can align it to the top.

halign2 = new Gtk.Alignment.c_new(0.0, 1.0, 0.0, 0.0);
help = new Gtk.Button.with_label("Help");
help.set_size_request(70, 30);
halign2.add(help);
table.set_row_spacing(3, 6);
table.attach(halign2, 0, 1, 4, 5, Gtk.AttachOptions.FILL,
    Gtk.AttachOptions.FILL, 0, 0);

The help button is placed into the alignment widget, so that it can be left aligned in its table cell. It is placed at the first column, fifth row.

var okButton = new Gtk.Button.with_label("OK");
okButton.set_size_request(70, 30);
table.attach(okButton, 3, 4, 4, 5, Gtk.AttachOptions.FILL,
    Gtk.AttachOptions.FILL, 0, 0);

Finally the ok button. It is placed at the fourth column, fifth row.

Windows
Figure: Windows

In this part of the JavaScript GTK tutorial, we mentioned layout management of widgets.