Rather than explicitly designing the layout of an application, defining the specific coordinates and dimensions of each element of the application, GTK+ uses relative positioning to indicate the placement of objects relative to each other. "Packing boxes" are the main object used to achieve this.
GTK+ uses a hierarchy of structures, with inherited properties passed down in an object-oriented fashion. All structures in GTK+ are type GtkObject, the root type, and most objects that perform some function are type GtkWidget, (other objects may be type GtkData). Of the various "widgets", those into which other objects may be places (e.g. a label inside a button) are type GtkContainer. However, a container may only contain one object. In order to draw several objects at once, we typically use a packing box, type GtkBox.
There are two main kinds of packing boxes, a vertical box (GtkVBox) and a horizontal box (GtkHBox). Any number of other objects may be packed into these boxes, and are displayed vertically or horizontally, respectively. Two-dimensional tables (GtkTable) may also be used to align objects both horizontally and vertically at the same time. The spacing between objects in a box or table may be defined when the container is created.
The sample code below provides a simple example. After
initialising GTK+ using gtk_init (&argc, &argv)
, which
allows standard GTK+ command line options to be processed for setting the
appearance of the application, the main
window is created. It is type GtkContainer, and so only one object may
be placed inside it. We placed a HBox inside it, which is then able
to hold two buttons, one which writes a simple message to standard
output, the other quits the program. Each object must be passed
through gtk_widget_show()
to actually appear on the
screen. This is typically done in "reverse" order - buttons first,
then the box they are contained in, then the whole window that the box
sits in - to avoid flickering as each object appears in turn on the
screen. This point is more of a issue for older, slower machines.
Note how the same printing function was attached to both buttons,
with extra data passed to the function to distinguish between the
two. Note also how two different functions (print and quit) are
attached to the same "clicked" signal for the "Quit" button. They are
executing in the order they were attached. Note lastly how the same
variable (GtkWidget *button) is used to refer to both buttons. Once the first
button is set up and there is no more need to refer to it, the
variable pointing to it can be recycled.
#include <gtk/gtk.h>
void WriteMessage( GtkWidget *widget, gpointer data )
{
g_print ("%s was pressed\n", (char *) data);
}
int main( int argc,
char *argv[] )
{
/* GtkWidget is the storage type for widgets */
GtkWidget *window;
GtkWidget *button;
GtkWidget *box;
gtk_init (&argc, &argv);
/* Create a new window */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "Sample GTK+ Application");
gtk_container_set_border_width (GTK_CONTAINER (window), 10);
/* It's a good idea to do this for all windows. */
gtk_signal_connect (GTK_OBJECT (window), "destroy",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
gtk_signal_connect (GTK_OBJECT (window), "delete_event",
GTK_SIGNAL_FUNC (gtk_exit), NULL);
/* create packing box */
box = gtk_hbox_new(FALSE,10);
/* Create a new button */
button = gtk_button_new_with_label ("OK");
/* Connect the "clicked" signal of the button to our callback */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (WriteMessage), (gpointer) "OK button");
gtk_widget_show(button);
gtk_box_pack_start (GTK_BOX (box), button, TRUE, FALSE, 10);
/* Create a new button */
button = gtk_button_new_with_label ("Quit");
/* Connect the "clicked" signal of the button to our callback */
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (WriteMessage), (gpointer) "Quit button");
gtk_signal_connect (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
gtk_widget_show(button);
gtk_box_pack_start (GTK_BOX (box), button, TRUE, FALSE, 10);
/* show all our widgets */
gtk_widget_show(box);
gtk_container_add (GTK_CONTAINER (window), box);
gtk_widget_show (window);
/* Rest in gtk_main and wait for the fun to begin! */
gtk_main ();
return(0);
}