Home

FreeBASIC GTK tutorial

This is FreeBASIC GTK tutorial. In this tutorial, we will create graphical user interface in the GTK library with the FreeBASIC language. The tutorial is suitable for beginners. Once you know the basics and you know how to use the GTK and the FreeBASIC together, you can just continue learning the GTK library from the GTK+ tutorial.

FreeBASIC is different from other languages that work with GTK. There is no such a binding like PyGTK or GTK#. In FreeBASIC, we directly call the C code in the program. This way, FreeBASIC is closely tied to the C language.

FreeBASIC

FreeBASIC is a popular BASIC (Beginner's All-purpose Symbolic Instruction Code) compiler. It appeared in 2004 and was influenced by QuickBASIC and C languages. FreeBASIC is a free, open-source, 32-bit BASIC compiler. To fully support many C libraries, many features have been added like pointers, preprocessor, macros, which cannot be found in other BASIC compilers.

GTK

The GTK is a library for creating graphical user interfaces. The library is created in C programming language. The GTK library is also called the GIMP Toolkit. Originally, the library was created while developing the GIMP image manipulation program. Since then, the GTK became one of the most popular toolkits under Linux and BSD Unix. Today, most of the GUI software in the open source world is created in Qt or in GTK. Language bindings exist for C++, Python, Perl, Java, C#, and other programming languages.

First example

In our first code example, we will center a small window on the screen.

' ZetCode FreeBASIC GTK tutorial
'
' This program centers a window on 
' the screen
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win

gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Center")
gtk_widget_set_size_request(win, 250, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

gtk_widget_show(win)
gtk_main()

END 0

This code centers a window on the screen. It is a mix of FreeBASIC and C code.

#include once "gtk/gtk.bi"

This is a header file needed to run GTK code from FreeBASIC.

#define NULL 0

There is no built-in NULL value in FreeBASIC. To more closely resemble the GTK C code, we define a NULL value.

Dim As GtkWidget Ptr win

We declare a pointer to the GtkWidget.

gtk_init(NULL, NULL)

We initiate the GTK library.

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)

We create a window which is a GtkWidget. The window type is GTK_WINDOW_TOPLEVEL. Toplevel windows have a titlebar and a border. They are managed by the window manager.

gtk_window_set_title(GTK_WINDOW(win), "Center")
gtk_widget_set_size_request(win, 250, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

These three lines set a title for the window, resize the window and position it to the center of the screen.

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

If we click on the x mark, or press Alt+F4 to terminate the application, a destroy signal is emitted. The window does not react to the destroy signal by default. We must explicitly terminate the application by connecting the destroy signal to the gtk_main_quit() function. There are two important characters. The underscore and the @ character. The underscore is a line continuation character in FreeBASIC. We must use it if a code line exceeds more that one line. The at @ character gives us the address of the gtk_main_quit() function. In C, a function name is an address to the function. This is not true in FreeBASIC that is why we use the @ character.

gtk_widget_show(win)

The window has been created in memory. Now we use the gtk_widget_show function to show the window on the screen.

gtk_main()

We enter the mainloop of the application. From this point, the application sits and waits for events to happen.

END 0

We finish FreeBASIC code.

$ fbc simple.bas
$ ./simple

We compile and run the example.

Simple example
Figure: Simple example

Close button

In the second example, we place a button widget on the window. First, we place a fixed container on the window and onto this container, we position our button. Clicking on the button will terminate the application.

' ZetCode FreeBASIC GTK tutorial
'
' In this example, we place a close
' button on the window. Clicking on the
' button will terminate the application.
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr fixed
Dim As GtkWidget Ptr button

gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Close")
gtk_widget_set_size_request(win, 250, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

fixed = gtk_fixed_new()
gtk_container_add(GTK_CONTAINER(win), fixed)
       
button = gtk_button_new_with_label("Close")
gtk_widget_set_size_request(button, 80, 35)

gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50)

g_signal_connect(G_OBJECT(button), "clicked", _
    G_CALLBACK (@gtk_main_quit), NULL)
      
gtk_widget_show_all(win)

gtk_main()

END 0

This is source code for the close button example.

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr fixed
Dim As GtkWidget Ptr button

We declare three variables. One for the toplevel window, which is the base skeleton of a GUI application. One for the container. The container is a special kind of widget. It is not visible. Its sole purpose is to contain other widget. In our case, the button widget.

fixed = gtk_fixed_new()
gtk_container_add(GTK_CONTAINER(win), fixed)

These two lines create a container widget and place it inside the window widget.

button = gtk_button_new_with_label("Close")
gtk_widget_set_size_request(button, 80, 35)

We create a button widget and make it 80x35 px.

gtk_fixed_put(GTK_FIXED(fixed), button, 50, 50)

We put a button into the container at x=50, y=50 coordinates. This is called absolute positioning. It is suitable for small examples, but in more complicated programs, we use layout managers.

g_signal_connect(G_OBJECT(button), "clicked", _
    G_CALLBACK (@gtk_main_quit), NULL)

When we click on the button, a clicked signal is emitted. The g_signal_connect() function connects a callback, in our case the built-in gtk_main_quit() function, to the clicked signal emitted by the button widget.

gtk_widget_show_all(win)

We have created three widgets. We could call gtk_widget_show() on each of them, or we call gtk_widget_show_all() on the window widget, which shows all three widgets in one step.

Close button
Figure: Close button

Displaying an image

In the following example, we display an image on the window.

' ZetCode FreeBASIC GTK tutorial
'
' This example shows an image on 
' the window
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"
#include once "gtk/gdk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr image

gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Red Rock")
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

gtk_window_set_resizable(GTK_WINDOW(win), FALSE)
gtk_container_set_border_width(GTK_CONTAINER(win), 2)

image = gtk_image_new_from_file("redrock.png")
gtk_container_add(GTK_CONTAINER(win), image)
      
gtk_widget_show_all(win)

gtk_main()

END 0

We show an image on the window.

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr image

We only have two widgets in this example. A window widget and an image widget.

gtk_window_set_resizable(GTK_WINDOW(win), FALSE)

The window cannot be resized. Note that we did not set a size for the window. In such a case, the window will automatically fit the size of the image.

gtk_container_set_border_width(GTK_CONTAINER(win), 2)

We put some empty space around the container.

image = gtk_image_new_from_file("redrock.png")
gtk_container_add(GTK_CONTAINER(win), image)

We create an image widget from a PNG file. We place the image to the window. The window is itself a simple container. It can contain exactly one widget.

Simple menu example

In the next code example, we will create a simple menu.

' ZetCode FreeBASIC GTK tutorial
'
' This example shows a simple menu
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr vbox

Dim As GtkWidget Ptr menubar
Dim As GtkWidget Ptr fmenu
Dim As GtkWidget Ptr fmi
Dim As GtkWidget Ptr qmi


gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Simple menu")
gtk_widget_set_size_request(win, 250, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

vbox = gtk_vbox_new(FALSE, 0)
gtk_container_add(GTK_CONTAINER(win), vbox)


menubar = gtk_menu_bar_new()
fmenu = gtk_menu_new()

fmi = gtk_menu_item_new_with_label("File")
qmi = gtk_menu_item_new_with_label("Quit")

gtk_menu_item_set_submenu(GTK_MENU_ITEM(fmi), fmenu)
gtk_menu_shell_append(GTK_MENU_SHELL(fmenu), qmi)
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fmi)
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0)

g_signal_connect(G_OBJECT(qmi), "activate", _
    G_CALLBACK(@gtk_main_quit), NULL)
      
gtk_widget_show_all(win)

gtk_main()

END 0

These code lines create a simple menu. It has only one menu item, which when selected will terminate the application. Creating a menubar is a bit confusing. We must bear in mind that both a menubar and menus are derived from the same widget, namely a menu shell. menu items are only valid childs for menus. They are also used to implement submenus.

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr vbox

Dim As GtkWidget Ptr menubar
Dim As GtkWidget Ptr fmenu
Dim As GtkWidget Ptr fmi
Dim As GtkWidget Ptr qmi

We have six variables for six widgets. One widget is a vertical box, which will set up the layout. A menubar is a horizontal widget, on which we place menus. The menus contain menu items, which do some actions. Like saving a document or terminating the application.

vbox = gtk_vbox_new(FALSE, 0)
gtk_container_add(GTK_CONTAINER(win), vbox)
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3)

We create a vertical box and make it to be the container for the toplevel window. The first parameter of the gtk_vbox_new() function is called the homogenous parameter. If set to TRUE, all widgets in a box has equal space allottings. We do not want this, because a menubar takes only a smaller portion of the window. The second parameter is space between children.

menubar = gtk_menu_bar_new()
fmenu = gtk_menu_new()

In this code we create a menubar and a menu.

fmi = gtk_menu_item_new_with_label("File")
qmi = gtk_menu_item_new_with_label("Quit")

Two menu items are created.

gtk_menu_item_set_submenu(GTK_MENU_ITEM(fmi), fmenu)

This code line implements a file menu. The logic is that the menubar is a menu shell. The file menu is also a menu shell. That's why we look at the file menu as a submenu or a subshell.

gtk_menu_shell_append(GTK_MENU_SHELL(fmenu), qmi)
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fmi)

Menu items are implemented by calling the gtk_menu_shell_append() function. The menu items are appended to menu shells. In our case, the quit menu item is appended to a file menu and also the file menu item is appended to the menubar.

gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0)

The gtk_box_pack_start() function call adds the menubar to the vertical box. The first parameter is the container, where we put the child widget. The second parameter is the child widget. The third parameter is expand parameter. Children with expand parameter set to TRUE will take up additional space from the vertical box. This additional space would be evenly distributed among them. We do not want the menubar to take up any additional space, so we set the expand parameter to FALSE. The fourth parameter has no effect if the expand is set to FALSE. The last parameter is padding, which adds some extra space among child widgets. We do not add any extra space.

g_signal_connect(G_OBJECT(qmi), "activate", _
    G_CALLBACK(@gtk_main_quit), NULL)

By selecting the quit menu item, we terminate the application.

Simple menu
Figure: Simple menu example

The enter signal

The following example will show, how we can react to an enter signal. The enter signal is emitted, when we enter the area of a widget with a mouse pointer.

' ZetCode FreeBASIC GTK tutorial
'
' In this code example, we react to the
' enter signal by changing the background
' color of a button widget
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr fixed
Dim As GtkWidget Ptr btn


Sub enter_button Cdecl (Byval widget As GtkWidget Ptr, _
    Byval dat As gpointer)
 
  Dim col As GdkColor

  col.red = 27000
  col.green = 30325
  col.blue = 34181
  gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, @col)
  
End Sub


gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "enter signal")
gtk_widget_set_size_request(win, 230, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

fixed = gtk_fixed_new()
gtk_container_add(GTK_CONTAINER(win), fixed)

btn = gtk_button_new_with_label("Button")
gtk_widget_set_size_request(btn, 80, 35)
gtk_fixed_put(GTK_FIXED(fixed), btn, 50, 50)

g_signal_connect(G_OBJECT(btn), "enter", _
    G_CALLBACK(@enter_button), NULL)
      
gtk_widget_show_all(win)

gtk_main()

END 0

We put a button widget into a fixed container. The enter_button() subroutine is called, when we enter the area of the button widget. Inside the subroutine, we change the background color of the button.

Sub enter_button Cdecl (Byval widget As GtkWidget Ptr, _
    Byval dat As gpointer)
...
End Sub

This is the enter_button() subroutine, in which we react to the enter signal. The Cdecl keyword specifies the calling convention of the subroutine. In this calling convention, any parameters are passed in the reverse order in which they are listed, that is, from right to left. In our case, it does not matter though.

Dim col As GdkColor

We create a local GdkColor variable. It is a structure used to describe a color in GTK applications.

col.red = 27000
col.green = 30325
col.blue = 34181

Here we set the color.

gtk_widget_modify_bg(widget, GTK_STATE_PRELIGHT, @col)

The gtk_widget_modify_bg() sets the background color for a widget in a particular state. In our case the state is the GTK_STATE_PRELIGHT, which is when the mouse pointer is over the widget. The third parameter is a pointer to the color structure.

g_signal_connect(G_OBJECT(btn), "enter", _
    G_CALLBACK(@enter_button), NULL)

Here we connect the enter_button() subroutine to the enter signal emitted by the button widget.

Check button example

In the following example, we put a check button into the fixed container. We will show and hide the title of the window by checking and unchecking of the check button.

' ZetCode FreeBASIC GTK tutorial
'
' This example a check button widget
' toggles the title of the window
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr cbtn
Dim As GtkWidget Ptr frame

Sub toggle_title Cdecl (Byval widget As GtkWidget Ptr, _
    Byval win As gpointer)

  If gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) Then
      gtk_window_set_title(win, "Check button")
  Else 
      gtk_window_set_title(win, "")
  End If
End Sub


gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Check button")
gtk_widget_set_size_request(win, 250, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

frame = gtk_fixed_new()
gtk_container_add(GTK_CONTAINER(win), frame)

cbtn = gtk_check_button_new_with_label("Show title")
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbtn), TRUE)
gtk_fixed_put(GTK_FIXED(frame), cbtn, 50, 50)

g_signal_connect(cbtn, "clicked", _
    G_CALLBACK(@toggle_title), cast(gpointer, win))
      
gtk_widget_show_all(win)

gtk_main()

END 0

This is the code to the check button example.

Sub toggle_title Cdecl (Byval widget As GtkWidget Ptr, _
    Byval win As gpointer)

We call the toggle_title() function if we click on the check button. In this case, we need pointers to two objects. We need a pointer to the check button to determine if it is checked or not. And we also need the pointer to the window to set or unset its title.

If gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)) Then
    gtk_window_set_title(win, "Check button")
Else 
    gtk_window_set_title(win, "")

We determine the state of the check button with the gtk_toggle_button_get_active() function. We set the title of the window with the gtk_window_set_title() function.

g_signal_connect(cbtn, "clicked", _
    G_CALLBACK(@toggle_title), cast(gpointer, win))

The last parameter of the g_signal_connect() is usually some data that we want to pass to the callback function. This time, we needed to pass another pointer to a window object. In such a case, we need to do casting. This is because the function expects a gpointer and the window is of GtkWidget type. FreeBASIC has a case keyword to do the casting.

Check button
Figure: Check button example

Combo box example

In the last example of the FreeBASIC GTK tutorial, we will present the combo box widget.

' ZetCode FreeBASIC GTK tutorial
'
' In this example, we present the combo box
' widget
'
' author Jan Bodnar
' last modified July 2010
' website www.zetcode.com

#include once "gtk/gtk.bi"

#define NULL 0

Dim As GtkWidget Ptr win
Dim As GtkWidget Ptr combo
Dim As GtkWidget Ptr fixed
Dim As GtkWidget Ptr label


Sub combo_selected Cdecl (Byval widget As GtkWidget Ptr, _
    Byval win As gpointer)
 
  Dim As gchar Ptr text

  text =  gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget))
  gtk_label_set_text(GTK_LABEL(win), text)
  g_free(text)
End Sub


gtk_init(NULL, NULL)

win = gtk_window_new(GTK_WINDOW_TOPLEVEL)
gtk_window_set_title(GTK_WINDOW(win), "Check button")
gtk_widget_set_size_request(win, 230, 150)
gtk_window_set_position(GTK_WINDOW(win), GTK_WIN_POS_CENTER)

g_signal_connect(G_OBJECT(win), "destroy", _
    G_CALLBACK (@gtk_main_quit), NULL)

fixed = gtk_fixed_new()

combo = gtk_combo_box_new_text()
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mandriva")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Fedora")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mint")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Gentoo")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Debian")

gtk_fixed_put(GTK_FIXED(fixed), combo, 50, 50)
gtk_container_add(GTK_CONTAINER(win), fixed)

label = gtk_label_new("-")
gtk_fixed_put(GTK_FIXED(fixed), label, 50, 110)

g_signal_connect(G_OBJECT(combo), "changed", _
    G_CALLBACK(@combo_selected), cast(gpointer, label))
      
gtk_widget_show_all(win)

gtk_main()

END 0

We have two widgets: combo box and a label. An option selected from the combo box will be shown in the label.

Dim As gchar Ptr text

text =  gtk_combo_box_get_active_text(GTK_COMBO_BOX(widget))
gtk_label_set_text(GTK_LABEL(win), text)
g_free(text)

In these lines, we retrieve the text from the combo box and set it to the label. We work with a pointer to the gchar. It is a basic type of the glib library, which is a foundation for the GTK library. We release the memory that was created while retrieving text from the combo box.

combo = gtk_combo_box_new_text()
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Ubuntu")
gtk_combo_box_append_text(GTK_COMBO_BOX(combo), "Mandriva")
...

Combo box widget is created and filled with data.

label = gtk_label_new("-")
gtk_fixed_put(GTK_FIXED(fixed), label, 50, 110)

Label widget is created and put insid the container.

g_signal_connect(G_OBJECT(combo), "changed", _
    G_CALLBACK(@combo_selected), cast(gpointer, label))

We plug a combo_selected() function to the changed signal of the combo box. We again do the casting.

A combo box widget
Figure: A combo box widget

This was the FreeBASIC GTK tutorial. We had several examples, which showed how we can work with the FreeBASIC language and the GTK library. These examples clearly showed that we mix FreeBASIC and C languages. Once you know how to bled these together, you just do the GTK programming. More about the GTK library can be found here.