Layout management in Java Gnome

In this chapter we will show how to lay out 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, HBox 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.

fixed.java
package com.zetcode;

import java.io.FileNotFoundException;

import org.gnome.gdk.Color;
import org.gnome.gdk.Event;
import org.gnome.gdk.Pixbuf;
import org.gnome.gtk.Fixed;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.Image;
import org.gnome.gtk.StateType;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.gtk.WindowPosition;

/**
 * ZetCode Java Gnome tutorial
 *
 * This program shows how to use
 * the Fixed container. 
 *
 * @author jan bodnar
 * website zetcode.com
 * last modified March 2009
 */

public class GAbsolute extends Window {

    private Pixbuf rotunda;
    private Pixbuf bardejov;
    private Pixbuf mincol;


    public GAbsolute() {
    
        setTitle("Absolute");
    
        initUI();
    
        connect(new Window.DeleteEvent() {
            public boolean onDeleteEvent(Widget source, Event event) {
                Gtk.mainQuit();
                return false;
            }
        });
    
        setDefaultSize(300, 280);
        setPosition(WindowPosition.CENTER);
        showAll();
    }
    
    public void initUI() {
    
        modifyBackground(StateType.NORMAL, new Color(15000, 15000, 15000));
        
        try {
            bardejov = new Pixbuf("bardejov.jpg");
            rotunda = new Pixbuf("rotunda.jpg");
            mincol = new Pixbuf("mincol.jpg");
        } catch (FileNotFoundException e) {
            System.out.println("Could not load images.");
            System.out.println(e.getMessage());
        }
        
        Image image1 = new Image(bardejov);
        Image image2 = new Image(rotunda);
        Image image3 = new Image(mincol);
        
        Fixed fix = new Fixed();
        
        fix.put(image1, 20, 20);
        fix.put(image2, 40, 160);
        fix.put(image3, 170, 50);
        
        add(fix);
    }
    
    public static void main(String[] args) {
        Gtk.init(args);
        new GAbsolute();
        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.

modifyBackground(StateType.NORMAL, new Color(15000, 15000, 15000));

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

bardejov = new Pixbuf("bardejov.jpg");

We load the image from the disk to the Pixbuf object.

Image image1 = new Image(bardejov);
Image image2 = new Image(rotunda);
Image image3 = new Image(mincol);

The Image is a widget that is used to display images. It takes Pixbuf object in the constructor.

Fixed fix = new Fixed();

We create the Fixed container.

fix.put(image1, 20, 20);

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

add(fix);

Finally, we add the Fixed container to the Window.

Fixed
Figure: Fixed

Alignment

The Alignment container controls the alignment and the size of its child widget.

alignment.java
package com.zetcode;

import org.gnome.gdk.Event;
import org.gnome.gtk.Alignment;
import org.gnome.gtk.Button;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.HBox;
import org.gnome.gtk.Label;
import org.gnome.gtk.VBox;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.gtk.WindowPosition;

/**
 * ZetCode Java Gnome tutorial
 *
 * This program places two buttons
 * in the right bottom corner of
 * the window. 
 *
 * @author jan bodnar
 * website zetcode.com
 * last modified March 2009
 */

public class GAlignment extends Window {

    public GAlignment() {
    
        setTitle("Alignment");
        
        initUI();
        
        connect(new Window.DeleteEvent() {
            public boolean onDeleteEvent(Widget source, Event event) {
                Gtk.mainQuit();
                return false;
            }
        });
        
        setDefaultSize(260, 150);
        setPosition(WindowPosition.CENTER);
        showAll();
    }
    
    public void initUI() {
        VBox vbox = new VBox(false, 5);
        HBox hbox = new HBox(true, 3);
        
        vbox.packStart(new Label(""));
        
        Button ok = new Button("OK");
        ok.setSizeRequest(70, 30);
        Button close = new Button("Close");
        
        hbox.add(ok);
        hbox.add(close);
        
        Alignment halign = new Alignment(1, 0, 0, 0);
        halign.add(hbox);
        
        vbox.packStart(halign, false, false, 3);

        add(vbox);
        setBorderWidth(5);
    }
    
    public static void main(String[] args) {
        Gtk.init(args);
        new GAlignment();
        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 an alignment container.

vbox.packStart(new Label(""));

This line will put an empty label into the vertical box. The label expands horizontally and vertically. This will make the next widget appended to the vertical box appear at the bottom of the window.

Button ok = new Button("OK");
ok.setSizeRequest(70, 30);
Button close = new Button("Close");
 
hbox.add(ok);
hbox.add(close);

The two buttons are added to the horizontal box.

Alignment halign = new Alignment(1, 0, 0, 0);
halign.add(hbox);

The horizontal box is added to an alignment widget. The alignment widget will align the buttons to the right. We must keep in mind that the alignment container takes only one child widget. That's why we must use boxes.

vbox.packStart(halign, false, false, 3);

The alignment widget is packed inside the vertical box.

Alignment
Figure: Alignment

Table

The Table widget arranges widgets in rows and columns.

calculator.java
package com.zetcode;

import org.gnome.gdk.Event;
import org.gnome.gtk.Button;
import org.gnome.gtk.Entry;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.Label;
import org.gnome.gtk.Menu;
import org.gnome.gtk.MenuBar;
import org.gnome.gtk.MenuItem;
import org.gnome.gtk.Table;
import org.gnome.gtk.VBox;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.gtk.WindowPosition;


/**
 * Java Gnome tutorial
 *
 * This program creates a calculator skeleton
 * with the Table container widget.
 *
 * @author jan bodnar
 * website zetcode.com
 * last modified March 2009
 */

public class GCalculator extends Window {

    public GCalculator() {
    
        setTitle("Calculator");
    
        initUI();
    
        connect(new Window.DeleteEvent() {
            public boolean onDeleteEvent(Widget source, Event event) {
                Gtk.mainQuit();
                return false;
            }
        });
    
        setDefaultSize(250, 230);
        setPosition(WindowPosition.CENTER);
        showAll();
    }
    
    
    public void initUI() {

        VBox vbox = new VBox(false, 2);
        
        MenuBar mb = new MenuBar();
        Menu filemenu = new Menu();
        MenuItem file = new MenuItem("File");
        file.setSubmenu(filemenu);
        mb.append(file);

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

        Table table = new Table(5, 4, true);

        table.attach(new Button("Cls"), 0, 1, 0, 1);
        table.attach(new Button("Bck"), 1, 2, 0, 1);
        table.attach(new Label(""), 2, 3, 0, 1);
        table.attach(new Button("Close"), 3, 4, 0, 1);

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

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

        table.attach(new Button("1"), 0, 1, 3, 4);
        table.attach(new Button("2"), 1, 2, 3, 4);
        table.attach(new Button("3"), 2, 3, 3, 4);
        table.attach(new Button("-"), 3, 4, 3, 4);

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

        vbox.packStart(new Entry(), false, false, 0);
        vbox.packStart(table, true, true, 0);
        
        add(vbox);
    }
    
    public static void main(String[] args) {
        Gtk.init(args);
        new GCalculator();
        Gtk.main();
    }
}

We use the Table widget to create a calculator skeleton.

Table table = new Table(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 same size. The size of all widgets is equal to the largest widget in the table container.

table.attach(new Button("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. In other words, it goes to the first cell of the table container. At 0, 0.

vbox.packStart(new Entry(), false, false, 0);

We first pack the Entry widget.

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

Then we add the table widget. We make it expand all the remaining space.

Calculator skeleton
Figure: Calculator skeleton

Expand and fill

The following example explains relationship between fill and expand parameters of the Box container.

boxes.java
package com.zetcode;

import org.gnome.gdk.Event;
import org.gnome.gtk.Button;
import org.gnome.gtk.Gtk;
import org.gnome.gtk.HBox;
import org.gnome.gtk.VBox;
import org.gnome.gtk.Widget;
import org.gnome.gtk.Window;
import org.gnome.gtk.WindowPosition;

/**
 * ZetCode Java Gnome tutorial
 *
 * This program explains the 
 * relationship between the fill
 * and expand parameters of the Box
 * container.
 *
 * @author jan bodnar
 * website zetcode.com
 * last modified March 2009
 */


public class GBoxes extends Window {

    public GBoxes() {
    
        setTitle("Boxes");
        
        initUI();
        
        connect(new Window.DeleteEvent() {
            public boolean onDeleteEvent(Widget source, Event event) {
                Gtk.mainQuit();
                return false;
            }
        });
    
        setDefaultSize(250, 150);
        setPosition(WindowPosition.CENTER);
        showAll();
    }
    
    
    public void initUI() {
        
        VBox vbox = new VBox(false, 5);
        
        HBox hbox1 = new HBox(false, 0);
        HBox hbox2 = new HBox(false, 0);
        HBox hbox3 = new HBox(false, 0);
        
        Button button1 = new Button("Button");
        Button button2 = new Button("Button");
        Button button3 = new Button("Button");
        
        hbox1.packStart(button1, false, false, 0);
        hbox2.packStart(button2, true, false, 0);
        hbox3.packStart(button3, true, true, 0);
        
        vbox.packStart(hbox1, false, false, 0);
        vbox.packStart(hbox2, false, false, 0);
        vbox.packStart(hbox3, false, false, 0);
        
        add(vbox); 
        
        setBorderWidth(8);
    }
    
    
    public static void main(String[] args) {
        Gtk.init(args);
        new GBoxes();
        Gtk.main();
    }
}

In our code example, we have a vertical base box and additional three horizontal boxes. And we have three buttons. We will see how combinatinos of expand and fill parameters will affect the layout.

We place three buttons inside the vertical box. The first parameter of the packStart() method is the widget, we put into the container. The second parameter is the expand, the third fill and the last parameter is the padding.

hbox1.packStart(button1, false, false, 0);

In this case, both expand and fill are false. The button does not grow and retains its initial position.

hbox2.packStart(button2, true, false, 0);

Here the expand parameter is set to true. Extra space is given to this button widget, but the widget does not grow or shrink. So in our case, the button will be centered horizontally and will retain its initial size.

hbox3.packStart(button3, true, true, 0);

Finally, we set both parameters to true. This will cause the button to take all the horizontal space allocated to it.

Expand and fill parameters
Figure: Expand and fill parameters

This was the first part of the layout management in Java Gnome.