Writing GTK+ Programs with the Free Pascal Compiler

Putting together a temperature conversion program demonstrates some of the features of using GTK+ and the Free Pascal compiler.

Being a fan of Delphi/Pascal for Windows programming, I have been curious about the Free Pascal project for quite some time. Free Pascal is an object-oriented compiled language that has been in development since 1993. I've also been interested in writing GUI applications for Linux, which recently prompted me to give Free Pascal a try. This article will briefly explain, based on my (limited) experience, how to write graphical applications using the GIMP Took Kit (GTK+) and the Free Pascal compiler on Linux.

The Free Pascal compiler (FPC) is a 32-bit compiler released under the GPL that is compatible with Turbo Pascal and implements Borland Delphi extensions, such as exceptions and overloading. It has been under development since 1993 and is available for a large number of operating systems including Linux, OS/2, Windows and DOS.

To install Free Pascal download the appropriate binary from the Free Pascal web site and follow the installation instructions. Don't forget to download the documentation, which is separate from the binary files. The Free Pascal compiler is written in Pascal, so don't download the source unless you already have a Pascal compiler on your machine. The standard installation provides the compiler, several Pascal tools, a complete set of system units, documentation and example programs.

The program in this article uses the GTK package included with the Free Pascal installation. It was written based on information from a tutorial called "Using GTK+ with FPC" (see Resources), examples included in the FPC doc directory and a series of articles written by Free Pascal's authors, which are available from the FPC site.

I wanted to do a bit more than the usual "Hello, World" example program, so the application presented here allows the user to enter temperatures using slider bars or text boxes and convert them between Fahrenheit and Celsius.

The Program

This article will focus more on the GTK+ aspects of the program and less on general Pascal programming. Please note that I use "controls" and "widgets" interchangeably throughout the text.

Listing 1. Compiled Sample Program

To use the GTK+ libraries, you need to include Free Pascal's GTK units in the program's uses clause, as shown below:

      glib, gdk, gtk

Initializing and running a GTK+ program is handled in three basic steps, listed the bottom of the program.

First, call gtk_init with any command-line arguments that were supplied:

   gtk_init(@argc, @argv);

This initializes everything needed to use the toolkit and terminates the application if the toolkit can't be initialized. The gtk_init routine strips any command line options it recognizes (e.g., which display to use) and returns the rest to your code.

Next, create the application's window and show it. This is handled by the two lines shown below. Instead of using a routine such as create_main_window, you could also put all the creation code inline.


Finally, call gtk_main(), which starts the GTK+ event handling loop.

Creating Windows and Widgets

In code, it is common for one control to affect another control's settings. In a small application it might be possible to handle this by defining all the controls globally, but this could be difficult to maintain in large programs. A common practice is to wrap a form and its controls in their own record type, then manipulate the controls through the record. In this program the TMainWindow type declaration wraps the applications main window and controls.

The main window and controls are created in the create_main_window routine. First the application's main window is created, and a caption is assigned to it with the following lines:

      Window := pGtkWindow(gtk_window_new(GTK_WINDOW_TOPLEVEL));
      gtk_window_set_title(Window, 'Temperature Conversion');

Next a horizontal packing box is created, hBox, to hold the various controls. Boxes are containers that hold widgets and provide rudimentary positioning and sizing control. A horizontal box positions controls on a line from left to right. A vertical box is also available that positions controls in a column. A layout of some complexity can be obtained by putting boxes inside of other boxes, something done in this program.

The individual controls are then created and packed into the horizontal box. The user interface consists of two vertical sliders and two text entry boxes, with labels above them and buttons below.

Creating a control won't automatically make it visible when the program is run; it also has to be shown, which can be accomplished in a couple of ways. One way would be to call the gtk_widget_show routine for each widget created. Another way is to call the gtk_widget_show_all routine with the container holding all the controls. That is the method used in this application, with the top-level container being the application's main window itself.

In order for controls to be able to respond to user input, signal-handling routines have to be assigned to them. Assigning a signal handler involves specifying the control to bind to, the signal to watch for, the address of the routine to call when the signal occurs and a piece of user-defined data.

The first signal handler assigned is the one for the main window's destroy event. This is called when the application is closed; it should free any used resources and then call GTK+'s gtk_main_quit routine.

This is accomplished by a call to gtk_signal_connect, binding the main window's destroy event to the program's quit_app procedure. gtk_signal_connect accepts the widget to monitor, the signal to watch for, the routine to handle the signal and a user-defined piece of data. In this program the user-defined data is the PMainWindow record created for this application. If you didn't want to pass any data to the signal handler, then you would just use Nil as the last parameter.

        gtk_signal_connect(pGtkObject(Window), 'destroy', 
                           GTK_SIGNAL_FUNC(@quit_app), Result);

Result holds an instance of PMainWindow, which was created at the beginning of the function. The quit_app routine is declared as shown with:

        procedure quit_app (widget: pGtkWidget; Window : PMainWindow); cdecl;

Notice the cdecl flag at the end of all signal handlers in the program. If you leave this off of your signal handler procedure declarations, the application will crash when they are called. Here is the explanation of cdecl from the FPC documentation:

A function that has a cdecl modifier, will be used with C calling conventions, that is, the caller clears the stack. Also the mangled name will be the name exactly as it is declared. cdecl is part of the function declaration, and hence must be present both in the interface and implementation section of a unit.

Vertical sliders for setting the temperatures are created (fahSlider, celSlider) with calls to the gtk_vscale_new function. The slider's display properties are set with calls to scale_set_default_values. The slider's initial, minimum, maximum and paging values are determined by GtkAdjustment widgets, which are created for each slider and supplied to the gtk_vscale_new calls.

When a slider is moved it emits a value_changed signal. Signal handlers (CsliderChanged and FsliderChanged) for this event are assigned to each slider.

A vertical packing box is created to hold the Fahrenheit label, text box and F to C button. The widgets are placed in the box, and the box is then added to the application's main horizontal box.

The same thing is done for the Celsius label and text box. Finally, the Celsius slider is placed in the application's window as the right-most control.



Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Nice Work

pickatutorial's picture

Nice work keep it up.

php gtk to exe

jigish thakar's picture

i need to create a exe file online of my gtk code

i m creating desktop widgets for my site
so can any one help with this thanks in advance....