This tutorial will cover tips on using Gnome GTK+ (Gimp ToolKit) to build a GUI application for cross platform deployment. Suggestions, tips and pitfalls are noted about the use of various GTK+ components.
GTK+ is a multi-platform GUI API library which includes the standard interface widgets. It is a component of the GNOME desktop and applications development environment which also includes multi-platform API's for graphics, video, window management, XML parsing, a thread library, internationalization, database access and general desktop application development. There is a GUI interface builder, Glade which generates a GTK+ source code skeleton for rapid application development. The API's support the "C" computer language. I usually encapsulate these calls within C++ objects where convenient. There is also a C++ framework available known as "gtkmm".
GTK is published under the GPL license and thus is free to use and redistribute.
Linux:
- RPM:
Systems which are Linux based will have GTK and Gnome as part of a regular install. The Gnome desktop and support services are NOT necessary to write a basic GTK+ GUI application.RedHat Linux RPMS's to install:
- gtk2
- gtk2-devel-2.XX
- gtk2-engines
- gtkhtml2-2.XX
- gtkam
- gtkam-gimp
- gtkglarea
- pango (Internationalized text handling)
- atk (Accessibility Toolkit)
- gdk-pixbuf-devel
- gdk-pixbuf-gnome
- gdk-pixbuf
- glib
- glade
- freetype
- fontconfig
- fontconfig-devel
- Building GTK+ from source:
The following must be done before configuring and building:- If installing to /opt, your PATH must include /opt/bin before
/bin and /usr/bin if conflicting versions of pkgconfig are pressent.
(export PATH=/opt/bin:$PATH) - Set the environment variable LD_LIBRARY_PATH to include /opt/lib.
(export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH) - Set environment variable PKG_CONFIG_PATH.
(export PKG_CONFIG_PATH=/opt/lib/pkgconfig:/usr/lib/pkgconfig)
Download the latest stable release from ftp://ftp.gtk.org/pub/gtk/. This requires downloading glib, atk, pango and gtk+ conpressed tar files. Also download from the "dependencies/" directory pkgconfig.
Uncompress: tar -xzf pkgconfig-0.15.0.tar.gz glib-2.4.7.tar.gz pango-1.4.1.tar.gz atk-1.6.1.tar.gz gtk+-2.4.13.tar.gz
For each subdirectory created configure and make:
config-0.15.0 ./configure --prefix=/opt make make install cd ../glib-2.4.7 ./configure --prefix=/opt make make install cd ../pango-1.4.1 ./configure --prefix=/opt make make install cd ../atk-1.6.1 ./configure --prefix=/opt make make install cd ../gtk+-2.4.13 ./configure --prefix=/opt make make install
Also see GTK+ building reference.
[Potential Pitfall]: Gtk+ configure error: "cofigure: error: Pango 1.2.0 and Xft backend is required for x11 target"
Test for problem with: pkg-config --modversion pangoxft
This command must return a version number or else this is an indication of a configuration problem.Actual problem is in configure of pango which gives error:
... checking for fontconfig >= 1.0.1... Package fontconfig was not found in the pkg-config search path. Perhaps you should add the directory containing `fontconfig.pc' to the PKG_CONFIG_PATH environment variable No package 'fontconfig' found configure: WARNING: No fontconfig found, skipping tests for FreeType and Xft ...
Fix: Set environment variable PKG_CONFIG_PATH. (export PKG_CONFIG_PATH=/opt/lib/pkgconfig:/usr/lib/pkgconfig)
This is so that the file fontconfig.pc can be located. This file is installed with the RPM fontconfig-devel. (required) - If installing to /opt, your PATH must include /opt/bin before
/bin and /usr/bin if conflicting versions of pkgconfig are pressent.
Microsoft Windows:
GTK can be compiled under Cygwin or Microsoft Visual C++.
MS/Windows install: I strongly recommend the GTK+ installer available from the Glade website:
MS/Windows GTK+ installer: http://gladewin32.sourceforge.net/
Two installers are available:
- gtk-win32-aio-2.4-rc16.exe: Installs the complete GTK development environment (headers, libraries, Glade GUI builder, GTK, GDK, Pango, etc.) Developers should use this installer to get the latest version of Glade.
- gtk-win32-2.4.6-rc2.exe: Installs GTK runtime environment.
GladWin32:
See: GladWin32: GTK+ GUI builder.
VC++ 6.0 Compiler/IDE:
If creating a new Visual C++ project:
- File + New and select "Win 32 Console Application". Enter a project name.
- The next dialog box allows one to define the type of application: Select "An empty project" + "Finish".
Note: If using VC++ 6.0, update VC++ 6.0 to SP5. Download and run to expand to subdir. Then run setupsp5.exe
Visual C++ 6.0 configuration:
- Add sockets library to support htonl(): Select "Project" + "Settings..." + "Link". Add "Object/library module": ws2_32.lib
- GTK:
VC++ compiler settings:- Project + Settings + C++ tab:
Category: C++ Language Check "Enable exception handling".
Category: Code Generation- Calling convention: _cdecl*
- Struct member alignment: 8 byte.
- Processor: Blend
Category: Precompiled Headers Check not using
Category: Preprocessor
Additional Include directories: C:\GTK\Win32\include,C:\libxml2\Win32\include - Project + Settings + Link tab:
- Category: General
Object/library modules: glib-2.0.lib gobject-2.0.lib gthread-2.0.lib gdk-win32-2.0.lib gdk_pixbuf-2.0.lib gtk-win32-2.0.lib atk-1.0.lib pango-1.0.lib libxml2.lib
Check: "Link incrementally" - Category: Input
Additional library path: C:\GTK\Win32\lib,C:\libxml2\Win32\lib
- Category: General
- Project + Settings + C++ tab:
System configuration:
- System Properties:
- Select the "Advanced" tab.
- Select the "Environment Variables ..." button.
- In the "User Variables" frame, edit the environment variable "PATH" and add:
C:\GTK\bin - Also set the following environment variables:
Environment Variable
LIB c:\GTK\lib GTK_BASEPATH c:\GTK INCLUDE c:\GTK\INCLUDE;c:\GTK\GTK-2.0;c:\GTK\GLIB-2.0; c:\GTK\PANGO-1.0; c:\GTK\ATK-1.0; c:\GTK\GTKGLEXT-1.0; c:\GTK\GTK-2.0\INCLUDE; c:\GTK\GLIB-2.0\INCLUDE; c:\GTK\GTKGLEXT\INCLUDE; c:\GTK\INCLUDE\LIBGLADE-2.0; c:\GTK\INCLUDE\LIBXML2;
Also see the YoLinux tutorial on MS/Visual C++ best practices so that the mess that this IDE can create is kept to a minimum.
The basic framework of a GTK+ program requires:
- the include file: gtk/gtk.h
- callbacks used to close the principal window.
- main program.
- a call to gtk_init (&argc, &argv);
- instantiation of main window
- attach main window callbacks to main window. i.e. Callbacks to close window.
- a container widget to attach other widgets to the main window and begin the "widget tree".
- Attach widgets to parent components.
- render the widgets including the container widgets and principal window.
- a call to the main event loop: gtk_main ();
#include <gtk/gtk.h> .. ... static gboolean delete_event( GtkWidget *widget, GdkEvent *event, gpointer data ) { return FALSE; } static void destroy( GtkWidget *widget, gpointer data ) { gtk_main_quit (); } int main( int argc, char *argv[] ) { GtkWidget *window_Widget; ... .. gtk_init (&argc, &argv); //instantiate principal parent window window_Widget = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window_Widget), "Example GTK Skeleton"); // Connect callbacks to main window g_signal_connect (G_OBJECT (window_Widget), "delete_event", G_CALLBACK (delete_event), NULL); g_signal_connect (G_OBJECT (window_Widget), "destroy", G_CALLBACK (destroy), NULL); gtk_container_set_border_width (GTK_CONTAINER (window_Widget), 10); // Call to container widget vBox_Widget = gtk_vbox_new (.......); ... .. // Attach widgets to container widget. gtk_box_pack_start (GTK_BOX (vBox_Widget), new_component_1_Widget, TRUE, TRUE, 0); ... .. // Attach container to main window. gtk_container_add (GTK_CONTAINER (window_Widget), vBox_Widget); ... .. gtk_widget_show (vBox_Widget); gtk_widget_show (window_Widget); gtk_main (); return 0; }
GTK is designed around a hierarchical class mechanism of widgets and objects of which GtkObject is the root. GtkObject provides the minimal set of information to support the GTK signal mechanism of callbacks which provide the functionality behind the GUI application. GTK is written in C and thus implements this mechanism with structures, composition and casting.
struct Child { GtkObject Parent // Appears first in structure definition ... }
Casting allows one to view just the object info held in all objects without knowing the details of the widget or derived object. This principal is built-in to the GTK object and widget api.
GTK Widgets form a hierarchy of widgets joined together in a tree. Thus all widgets must be "linked" together with container or packing widgets to create this tree. It is this tree which is traversed for rendering of the GUI and for signal/callback handling. Thus an object which is "destroyed" will destroy the entire branch unless it is re-attached at some point in the hierarchy.
There are numerous widgets defined and available for use. One can also generate thier own widgets and compose widgets from combinations of other widgets.
Examples:
- Push Buttons
- Menu Widget
- Radio Button
- Check Button
- Scroll Bar
- Drawing Area
- Tree View
- Text View
- Text Entry Box
- Combo Box
- Scroll Bars (horizontal and vertical)
Signals can then be associated with a widget so that an action (i.e. button release) on a Button widget will invoke a callback function to be executed and perform the desired task (i.e. process or display something or both).
Container, Alignment and Packing widgets are used to place
display widgets and other container widgets within a window frame. They
do not take any form when rendered. (invisible)
Types:
- gtk_container_add()
This will hold a single widget.
- gtk_alignment_new()
Position a widget within it's window.
Use the function gtk_alignment_set() to control layout and spacing. - gtk_fixed_new()
Fix widget position in window relative to upper left hand corner.
Use the functions gtk_fixed_put(), gtk_fixed_move(), gtk_fixed_set_has_window() and gtk_fixed_get_has_window() to control layout. - gtk_layout_new()
Layout in infinite scrolling area.
Use the functions gtk_layout_put(), gtk_layout_move(), gtk_layout_set_size(), gtk_layout_get_hadjustment(), gtk_layout_get_vadjustment(), gtk_layout_set_hadjustment() and gtk_layout_set_vadjustment() to control layout and spacing. - gtk_hbox_new()
Horizontal boxes
Use the functions gtk_box_pack_start() and gtk_box_pack() to control layout and spacing.
Also see gtk_hbutton_box_new(). - gtk_vbox_new()
Vertical Boxes
Use the functions gtk_box_pack_start() and gtk_box_pack() to control layout and spacing.
Also see gtk_vbutton_box_new(). - gtk_table_new()
Table
Use the functions gtk_table_attach(), gtk_table_attach_defaults(), gtk_table_set_row_spacing(), gtk_table_set_col_spacing(), to control layout and spacing.
Signals allow for a routine to be called when a user interaction occurs. Use the routine g_signal_connect() to attach a "callback" function to a user interaction ("signal").
The signals have pre-defined names. Each widget has a defined list of signals which can act on the widget. For example, a "window" widget may have the signals:
- activate_focus
- frame_event
- move_focus
- ...
- delete_event
- button_press_event
- button_release_event
- expose_event
- hide_event
- show
- ...
Define the callback functions:
.. ... // Calback function definitions gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer data) { gtk_main_quit(); return FALSE; } void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } ... ..
Associate the callback function to a user action performed on a specified widget:
.. ... // Callback is invoked when signal "delete_event" is applied by the user to // the widget "mainWindow". This occurs when the user selects the X in the // window corner to close/terminate the window. g_signal_connect((gpointer) mainWindow, "delete_event", G_CALLBACK(delete_event), NULL); // Attach the callback routine destroy to the action "destroy" when applied to the widget mainWindow g_signal_connect((gpointer) mainWindow, "destroy", G_CALLBACK(destroy), NULL); ... ..
The list of signals available are dependent on the widget. It is for this reason that the GUI builder Glade is very useful.
Passing C++ object to a Signal:
static void on_applyButton_clicked(GtkWidget *button, gpointer data) { CclassDef *obj = static_cast<CclassDef *>(data); assert(obj != NULL); gtk_widget_destroy((GTK_WIDGET(obj->getWindowPtr())); } .. ... // Within class function g_signal_connect((gpointer) applyButton, "clicked", G_CALLBACK(on_applyButton_clicked), this); ... ..
Signal inheritance:
The object oriented nature of GTK allows a widget to inherit the ability to receive signal types of the parents in its inheritance tree. Thus signals inherit pre-defined behaviors already configured in the GTK GUI and components. A signal daisy-chain is processed which executes the user defined signals and then processes the inherited signals. One may break this chain of events so that only your signal handlers are processed, To prevent inheritance of predefined signal behaviors, the signal function must return a boolean. Return "true" to break inheritance. Return "false" to maintain the behavior of predefined parent signals such that the chain of inherited signals are maintained and processed after your signal is processed.
Example:
GTK predefines the behavior of the up/down arrow keys for GUI focus navigation
traversal of the interactive GUI control widgets.
If using the up/down arrow within a text entry box we would need to deactivate
the predefined navigation of the GUI by returning "true" to break the chain.
This example handles text entry and up/down arrows with two callbacks attached to the same widget.
// Callback to handle text entry void on_entry_activate(GtkWidget *widget, gpointer data) { char *string_entered = gtk_editable_get_chars(GTK_EDITABLE(widget), 0, -1); if(strlen(string_entered) > 0) { .. ... } g_free(string_entered); } // Callback to handle up/down arrows gboolean on_entryBox1_key_press_event (GtkWidget *widget, GdkEventKey *event, gpointer user_data) { gboolean breakInheritance = true; .. ... if(event->keyval == 65362) // Up arrow { gtk_entry_set_text(GTK_ENTRY(widget), text_string_prev); gtk_editable_set_position(GTK_EDITABLE(widget), strlen(text_string_prev); } else if(event->keyval == 65364) // down arrow { if(isEndList) { gtk_entry_set_text(GTK_ENTRY(widget), ""); gtk_editable_set_position(GTK_EDITABLE(widget), ""); } else { gtk_entry_set_text(GTK_ENTRY(widget), text_string_next); gtk_editable_set_position(GTK_EDITABLE(widget), strlen(text_string_next); } } else { breakInheritance = false; } } .. ... // In main code tie callbacks to widget. g_signal_connect((gpointer) textEntryWidget, "activate", G_CALLBACK(on_entry_activate), NULL); gtk_signal_connect (GTK_OBJECT (textEntryWidget), "key_press_event", GTK_SIGNAL_FUNC (on_entryBox1_key_press_event), NULL); ... ..
Also see: GtkKeySnoopFunc()
- If trying to fix a crash, don't "gtk_widget_show()" a widget until it has been attached to a parent
widget first.
The widget structure is a tree hierarchy starting from the parent window and branching to each and every widget.
Change/assign button color:
(code snippet)
GdkColor colorButton; GtkWidget *button_Widget; colorButton.red=65535; colorButton.green=0; colorButton.blue=0; gtk_color_button_set_color(button_Widget,colorButton); gtk_widget_show (button_Widget); ... ..
GdkColor colorRed; GtkWidget *button_Widget; gdk_color_parse ("red", &colorRed); ... ... button_Widget = gtk_button_new_with_label("Button"); gtk_widget_modify_base (button_Widget, GTK_STATE_NORMAL, &colorRed); gtk_widget_modify_fg (button_Widget, GTK_STATE_NORMAL, &colorRed); gtk_widget_modify_bg (button_Widget, GTK_STATE_NORMAL, &colorRed); gtk_widget_modify_bg (button_Widget, GTK_STATE_PRELIGHT, &colorRed); gtk_widget_show (button_Widget); ... ..
Color declaration and assignment:
(code snippet)
... static GdkColor colorGreen; static GdkColor colorYellow; static GdkColor colorRed; static GdkColor colorBlack; ... gdk_color_parse("green", &colorGreen); gdk_color_parse("yellow", &colorYellow); gdk_color_parse("red", &colorRed); gdk_color_parse("black", &colorBlack); ...
Text labels can be placed anywhere on the GUI display. Placement is usually with a container such as "vbox" or "hbox". Note that the text can be modified using the html/xml tag "small".
... GtkWidget *textLabel_Widget; char displayLabel[64]; char *textLabel="Display Label"; sprintf(displayLabel, "<small>%s</small>", textLabel); textLabel_Widget = gtk_label_new (NULL); gtk_label_set_markup(GTK_LABEL (textLabel_Widget), displayLabel); gtk_label_set_justify(GTK_LABEL (textLabel_Widget),GTK_JUSTIFY_LEFT); gtk_misc_set_alignment (GTK_MISC (textLabel_Widget), 0, 0.5); gtk_widget_show (textLabel_Widget); ...
Pango is the framework for layout and rendereing of internationalized text in GTK+. On Linux systems the final rendering is performed by X-Windows. Pango uses Unicode characters internally. Examples here use UTF-8 which is compatable with existing ASCII 8-bit software. Offsets in Pango are counted in bytes and not characters. While Pango was created to support non-Roman character languages like Japanese, Greek and Arabic, only English UTF-8 examples are shown.
Pango also supports a simple subset of HTML/XML for text attributes:
HTML Tag | Description |
---|---|
<b> | Bold |
<big> or <span size="larger"> |
Increase font size |
<small> or <span size="smaller"> |
Decrease font size |
<i> | Italic |
<s> | Strikethrough |
<subs> | Subscript |
<sup> | superscript |
<tt> | Monospace Font |
<u> | Underline |
<span> | Use with attributes to specify rendering:
|
The XML tree root element tags are <markup> and </markup> but it is not necessary to reference or include them.
Example:
Pango converts HTML markup string into a text string and list of attributes and enables layout and rendering.
#include <gtk/gtk.h> .. ... gchar *stringMarkupText = "<span foreground=\"blue\"><b>Bold</b> <u>is</u> <i>beautiful</i></span>"; gchar *stringPlainText; PangoAttrList *attrList; GtkWidget *displayLabelWidget; ... pango_parse_markup(stringMarkupText, -1, 0, &attrList, &stringPlainText, NULL, NULL); displayLabelWidget = gtk_label_new(stringPlainText); gtk_label_set_attributes(GTK_LABEL(displayLabelWidget), attrList); ... gtk_widget_show(displayLabelWidget); ...
Note: One may also use the equivalent GTK+ calls to gtk_label_set_markup() and the function above in the Text Labels example.
Result:
Links:
The first series of examples are for the GTK text_entry and the second set briefly cover the GTK text_view widget. The text entry widget is preffered as it supports more features and fully supports view only functionality.
GTK Text Entry Widget:
Creates a new text entry/display widget.
.. ... GtkWidget *text_entry_Widget = gtk_entry_new(); ... ..
Set entry text box background color:
.. ... gtk_widget_modify_base(text_entry_Widget, GTK_STATE_NORMAL, &colorBlack); ... ..
Display entry text in green.
.. ... gtk_widget_modify_text(text_entry_Widget, GTK_STATE_NORMAL, &colorGreen); ... ..
Modify entry text box style so text is BOLD:
.. ... GtkStyle *style = gtk_widget_get_style(text_entry_Widget); pango_font_description_set_weight(style->font_desc, PANGO_WEIGHT_BOLD); gtk_widget_modify_font(text_entry_Widget, style->font_desc); ... ..
Set entry text box size:
.. ... int text_width = 20; // Width of field in characters gtk_entry_set_width_chars(GTK_ENTRY(text_entry_Widget), text_width); ... ..
Set entry text box editable(default)/not editable:
.. ... bool text_is_editable = false; // Flag indicating if text field is editable or display only if (!text_is_editable) { gtk_editable_set_editable(GTK_EDITABLE(text_entry_Widget), FALSE); GTK_WIDGET_UNSET_FLAGS(text_entry_Widget, GTK_CAN_FOCUS); } ... ..
Display text in the GTK text entry box widget.
.. ... char _txtBuffer = "Display Text"; gtk_entry_set_text(GTK_ENTRY(text_entry_Widget), _txtBuffer); ... ..
Set display box as "insensitive". Display background as "grayed out" and disable user interaction.
.. ... gboolean _isSensitive = false; gtk_widget_set_sensitive(text_entry_Widget, _isSensitive); ... ..
- Sensitive: boolean set to true
Interaction with widget (text entry widget) is allowed. - Insensitive: boolean set to false
Interaction with widget (text entry widget) is not allowed. Background is "grayed out".
Display tooltip when hovering text box:
.. ... char *toolTipsText = "Tool Tips Text Displayed When Mouse Hovers Text Entry Box"; GtkTooltips *tooltipsA; ... tooltipsA = gtk_tooltips_new(); ... gtk_tooltips_set_tip(tooltipsA, text_entry_Widget, toolTipsText, NULL); ... ..
Text display box with modified background and text:
![gtk Text Entry Box Display](images/gtkTextEntryBox.gif)
Widgets and g_Threads:
Note: If updating the text with new data from a spawned GTK thread which listens to a socket or performs digital acquisition, one must protect the code segment with a GTK mutex. This must be applied to the calls in the spawned thread and not in the GUI main thread. This will avoid GUI update conflicts between gtk_main() and the GTK calls invoked in the thread. Thread support and stability is significantly improved in GTK+ 2.6.2.
.. ... gdk_threads_enter(); // Protect from gtk main loop which also performs a gtk_entry_set_text. gtk_entry_set_text(GTK_ENTRY(text_entry_Widget), _txt); gdk_flush(); gdk_threads_leave(); ... ..
The required basic gdk threads framework:
.. ... if( !g_thread_supported() ) { g_thread_init(NULL); gdk_threads_init(); // Called to initialize internal mutex "gdk_threads_mutex". printf("g_thread supported\n"); } else { printf("g_thread NOT supported\n"); } ... .. .. ... gdk_threads_enter(); gtk_main(); gdk_threads_leave(); ... ..
[Potential Pitfall]: You will create a deadlock condition if you try to update a widget before it has been realized.
GTK Text View Widget:
This is an alternate method of displaying text in a box. I prefer using a text entry widget as it has more available options.
.. ... GtkWidget *textView_Widget; int text_width = 20; // Width of field char *txtBuffer = "Display Text"; textView_Widget = gtk_text_view_new (); gtk_widget_set_usize (textView_Widget, text_width, -2); gtk_text_view_set_editable( GTK_TEXT_VIEW (textView_Widget), FALSE); gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW (textView_Widget), FALSE); gtk_text_view_set_pixels_above_lines( GTK_TEXT_VIEW (textView_Widget), 5); gtk_text_view_set_left_margin( GTK_TEXT_VIEW (textView_Widget), 3); gtk_text_buffer_set_text(gtk_text_view_get_buffer (GTK_TEXT_VIEW (textView_Widget)), txtBuffer, -1); gtk_widget_modify_text (textView_Widget, GTK_STATE_NORMAL, &colorGreen); gtk_widget_modify_base (textView_Widget, GTK_STATE_NORMAL, &colorBlack); gtk_widget_show (textView_Widget); ... .. i
The following code snippet shows how to embed and display an image within software. Any bitmap image (gif, jpeg, etc) can be converted to an "xpm" file using image manipulation software such as XV or Gimp and performing a "Save as ...".
[Potential Pitfall]: If your application core dumps when trying to employ pixmaps, try one of these clearly opposite solutions:
- Place "gtk_widget_show(window)" near the end just before gtk_main()
- Call "gtk_widget_show(window)" after declaration and attributes are set. (Fairly standard)
Transparent xpm include file: green_DOT.xpm
static char *green_DOT_xpm[] = { /* width height num_colors chars_per_pixel */ " 20 20 22 1", /* colors */ ". c #000000", "# c #010301", ... "t c None", /* Transparent background. */ ... /* pixels */ "tttttttttttttttttttt", "ttttttt.....tttttttt", "ttttt#hklmlkd.tttttt", ... };
Embedding the pixmap in your display:
#include <gtk/gtk.h> #include "green_DOT.xpm" ... GtkWidget *window; GtkWidget *hbox; GtkWidget *image; GdkPixmap *icon; GdkBitmap *icon_mask; GtkStyle *style; ... window = gtk_window_new (GTK_WINDOW_TOPLEVEL); ... if(!window)printf("No window. Bad!\n"); style = gtk_widget_get_style( window ); icon = gdk_pixmap_create_from_xpm_d(GTK_WIDGET(window)->window, &icon_mask, &style->bg[GTK_STATE_NORMAL], green_DOT_xpm); image = gtk_pixmap_new(icon, icon_mask); gtk_widget_show(image); gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0); ... gtk_widget_show (window); /* Do NOT place after "gtk_window_new". */ g_object_unref(icon); g_object_unref(icon_mask); gtk_main (); ...
Using images to display status: It may be necessary to use pixmaps to display status thus changing the display. In this example we generate and display three color boxes (grey, red and green) but only display one at a time depending on which is relevant.
Generate the pixmap widgets: (See above discussion to see full source code.)
// Global variables GtkWidget *redBox; GtkWidget *greenBox; GtkWidget *greyBox; ... greyBox = gtk_pixmap_new(_icon_grey, _icon_mask_grey); ... greenBox = gtk_pixmap_new(_icon_green, _icon_mask_green); ... redBox = gtk_pixmap_new(_icon_red, _icon_mask_red); ... gtk_widget_show(greyBox); // Start by displaying the Grey box ...
Attach all three pixmap widgets to the same location:
... GtkWidget *window; GtkWidget *hbox1; ... hbox1 = gtk_hbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), hbox1); ... // Attach both images to the same place!! gtk_box_pack_start(GTK_BOX(hbox1), greyBox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), greenBox, TRUE, TRUE, 0); gtk_box_pack_start(GTK_BOX(hbox1), redBox, TRUE, TRUE, 0); ... // Position both images in the same location gtk_misc_set_alignment(GTK_MISC(greyBox), 1, 0.5); gtk_misc_set_alignment(GTK_MISC(greenBox), 1, 0.5); gtk_misc_set_alignment(GTK_MISC(redBox), 1, 0.5); ... gtk_widget_show(hbox1); ...
Callbacks to switch displays:
Display green box:
... gtk_widget_hide(greyBox); gtk_widget_hide(redBox); gtk_widget_show(greenBox); ...
Display red box:
... gtk_widget_hide(greyBox); gtk_widget_hide(greenBox); gtk_widget_show(redBox); ...
The three images are all located in the same place but only one is displayed at a time.
![](images/gtkSwapPixmaps-Grey.gif)
![](images/gtkSwapPixmaps-Green.gif)
![](images/gtkSwapPixmaps-Red.gif)
Source code to this example: gtkSwapPixmaps.c
Compile:
- gcc gtkSwapPixmaps.c -o gtkSwapPixmaps `pkg-config --cflags --libs gtk+-2.0`
OR - gcc gtkSwapPixmaps.c -o gtkSwapPixmaps -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/pango-1.0 -I/usr/X11R6/include -I/usr/include/freetype2 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -Wl,--export-dynamic -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
Creates a check box button. This button is not "grayed out" when insensitive but they are unselectable until the state is changed to GTK_STATE_SENSITIVE (default).
... GtkWidget *button_Widget = gtk_check_button_new(); GtkStyle *style = gtk_widget_get_style(button_Widget); gtk_widget_modify_base(button_Widget, GTK_STATE_INSENSITIVE, &style->base[GTK_STATE_NORMAL]); gtk_widget_modify_text(button_Widget, GTK_STATE_INSENSITIVE, &style->text[GTK_STATE_NORMAL]); return button_Widget; OR gtk_widget_show(button_Widget); ...
The GNOME GTK+ GUI builder Glade will generate a software skeleton for an application which is compilable and executable. Glade will also include many support routines which are useful whether you use Glade or not in the construction of your GTK+ application. These support routines are found in the Glade generated file src/support.c.
Glade lookup routine lookup_widget() (See Glade generated file src/support.c): Start at tree root "widget" and return "GtkWidget" corresponding to the "widget_name" (index to lookup table). If the widget tree root is given, then this routine can traverse the widget tree and return the GtkWidget pointer to the widget identified by name. This eliminates the need to pass all possible pointers used in processing but instead just pass around one, the root (i.e. main window) widget, and use lookup_widget() to locate all the others. Actually any widget can be passed as the routine will traverse the tree to first find the root ans then scan the tree. One must assign widget names using the Glade macro GLADE_HOOKUP_OBJECT. Glade will generate these associations in the generated file src/interface.c.
.. ... // Macro definition: #define GLADE_HOOKUP_OBJECT(component,widget,name) \ g_object_set_data_full (G_OBJECT (component), name, \ gtk_widget_ref (widget), (GDestroyNotify) gtk_widget_unref) #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \ g_object_set_data (G_OBJECT (component), name, widget) ... .. ... /* Store pointers to all widgets, for use by lookup_widget(). */ GLADE_HOOKUP_OBJECT_NO_REF(mainWindow, mainWindow, "mainWindow"); GLADE_HOOKUP_OBJECT(mainWindow, vbox1, "vbox1"); GLADE_HOOKUP_OBJECT(mainWindow, mainMenuBar, "mainMenuBar"); GLADE_HOOKUP_OBJECT(mainWindow, fileMenuitem, "fileMenuitem"); GLADE_HOOKUP_OBJECT(mainWindow, fileMenuitem_menu, "fileMenuitem_menu"); GLADE_HOOKUP_OBJECT(mainWindow, quitMenuItem, "quitMenuItem"); ... ..
At the heart of the GLADE_HOOKUP_OBJECT macro is the GObject call g_object_set_data_full. This enables the association of text labels to widget pointers. One may add an association directly by using this routine.
The widget pointer can then be found using the widget identifier. i.e.:
.. ... GtkWidget *widgetPtrToBefound = lookup_widget(window, "name_of_widget_ie_vbox1"); assert(widgetPtrToBefound != NULL); ... ..
The routine lookup_widget as generated by Glade in the file src/support.c.
.. ... widget. GtkWidget* lookup_widget(GtkWidget *widget, const gchar *widget_name) { GtkWidget *parent, *found_widget; for (;;) { if (GTK_IS_MENU(widget)) parent = gtk_menu_get_attach_widget(GTK_MENU(widget)); else parent = widget->parent; if (!parent) parent = (GtkWidget*) g_object_get_data(G_OBJECT(widget), "GladeParentKey"); if (parent == NULL) break; widget = parent; } found_widget = (GtkWidget*) g_object_get_data(G_OBJECT(widget), widget_name); if (!found_widget) g_warning ("Widget not found: %s", widget_name); return found_widget; } ... ..
- GTK Links:
- GTK Home Page: http://gtk.org
- GNOME Developer Home Page http://developer.gnome.org
- Colors - resource file and widget states.
- PDF tutorial
- GTK for Windows: http://gladewin32.sourceforge.net - All in one installer (Ivan Wong)
- Widgets (not GTK native):
- YoLinux.com Tutorials: