Menus and Toolbars in GTK+
In this part of the GTK+ programming tutorial, we will work with menus and toolbars.A menubar is one of the most common parts of the GUI application. It is a group of commands located in various menus. While in console applications you had to remember all those arcane commands, here we have most of the commands grouped into logical parts. There are accepted standards that further reduce the amount of time spending to learn a new application.
Simple menu example
In our first example, we will create a menubar with one file menu. The menu will have only one menu item. By selecting the item the application quits.#include <gtk/gtk.h>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 children for menus. They are also used to implement submenus.
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *filemenu;
GtkWidget *file;
GtkWidget *quit;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_window_set_title(GTK_WINDOW(window), "menu");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
menubar = gtk_menu_bar_new();
filemenu = gtk_menu_new();
file = gtk_menu_item_new_with_label("File");
quit = gtk_menu_item_new_with_label("Quit");
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(quit), "activate",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
menubar = gtk_menu_bar_new();In this code we create a menubar and a menu.
filemenu = gtk_menu_new();
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);This code line implements a file menu. The logic is that the menubar is a menu shell. 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(filemenu), quit);Menu items are implemented by calling the gtk_menu_shell_append() function. menu items are appended to menu shells. In our case, quit menu item is appended to a file menu and also the file menu item is appended to the menubar.
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
g_signal_connect(G_OBJECT(quit), "activate",By selecting the quit menu item, we quit the application.
G_CALLBACK(gtk_main_quit), NULL);
Figure: Simple menu
Image menus, mnemonics & accelerators
In the next example, we will further explore the functionality that we can use in GTK+. Accelerators are keyboard shortcuts for activating a menu item. Mnemonics are keyboard shortcuts for GUI elements. They are represented as underlined characters.Note, that you might have Gnome configured not to show menu images. To turn the menu images On/Off, you launch the gconf-editor and go to /desktop/gnome/interface/menus_have_icons. Check/uncheck the option.
#include <gtk/gtk.h>The example shows, how to add an image to our menu item. How to set up an accelerator and how to use mnemonics in our GTK+ applications.
#include <gdk/gdkkeysyms.h>
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *filemenu;
GtkWidget *file;
GtkWidget *new;
GtkWidget *open;
GtkWidget *quit;
GtkWidget *sep;
GtkAccelGroup *accel_group = NULL;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_window_set_title(GTK_WINDOW(window), "menu");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
menubar = gtk_menu_bar_new();
filemenu = gtk_menu_new();
accel_group = gtk_accel_group_new();
gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
file = gtk_menu_item_new_with_mnemonic("_File");
new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);
open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
sep = gtk_separator_menu_item_new();
quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);
gtk_widget_add_accelerator(quit, "activate", accel_group,
GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(file), filemenu);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), new);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), open);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), sep);
gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), quit);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), file);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(quit), "activate",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
accel_group = gtk_accel_group_new();An accelerator group is a group of keyboard accelerators, typically attached to a toplevel window. Here we create Ctrl + q keyboard accelerator.
gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
...
quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT, accel_group);
gtk_widget_add_accelerator(quit, "activate", accel_group,
GDK_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
file = gtk_menu_item_new_with_mnemonic("_File");To create a mnemonic, we call the gtk_menu_item_new_with_mnemonic()function. We select the file menu item by pressing the Alt + F.
new = gtk_image_menu_item_new_from_stock(GTK_STOCK_NEW, NULL);Here we create two image menu items. By setting the second parameter of the function to NULL, we automatically create accelerators. We provide an image and text for our menu item from internal GTK+ resources.
open = gtk_image_menu_item_new_from_stock(GTK_STOCK_OPEN, NULL);
sep = gtk_separator_menu_item_new();Menu items can be separated by a horizontal separator. This way we can put menu items into some logical groups.
Figure: Menu example
Check menu item
A GtkCheckMenuItem is a menu item with a check box.#include <gtk/gtk.h>In our code example we show a check menu item. If the check box is activated, the statusbar widget is shown. If not, the statusbar is hidden.
void toggle_statusbar(GtkWidget *widget, gpointer statusbar)
{
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {
gtk_widget_show(statusbar);
} else {
gtk_widget_hide(statusbar);
}
}
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *menubar;
GtkWidget *viewmenu;
GtkWidget *view;
GtkWidget *tog_stat;
GtkWidget *statusbar;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_window_set_title(GTK_WINDOW(window), "view statusbar");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
menubar = gtk_menu_bar_new();
viewmenu = gtk_menu_new();
view = gtk_menu_item_new_with_label("View");
tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");
gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(tog_stat), TRUE);
gtk_menu_item_set_submenu(GTK_MENU_ITEM(view), viewmenu);
gtk_menu_shell_append(GTK_MENU_SHELL(viewmenu), tog_stat);
gtk_menu_shell_append(GTK_MENU_SHELL(menubar), view);
gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 3);
statusbar = gtk_statusbar_new();
gtk_box_pack_end(GTK_BOX(vbox), statusbar, FALSE, TRUE, 1);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect(G_OBJECT(tog_stat), "activate",
G_CALLBACK(toggle_statusbar), statusbar);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
tog_stat = gtk_check_menu_item_new_with_label("View Statusbar");The gtk_check_menu_item_new_with_label() function call creates a new check menu item.
if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) {If the check box in the menu item is activated, we show the statusbar widget. Otherwise the statusbar is hidden.
gtk_widget_show(statusbar);
} else {
gtk_widget_hide(statusbar);
}
Figure: Check menu item
A toolbar
Menus group commands that we can use in application. Toolbars provide a quick access to the most frequently used commands.#include <gtk/gtk.h>The code example creates simple toolbar example.
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *toolbar;
GtkToolItem *new;
GtkToolItem *open;
GtkToolItem *save;
GtkToolItem *sep;
GtkToolItem *exit;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_window_set_title(GTK_WINDOW(window), "toolbar");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
toolbar = gtk_toolbar_new();
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);
new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
open = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), open, -1);
save = gtk_tool_button_new_from_stock(GTK_STOCK_SAVE);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), save, -1);
sep = gtk_separator_tool_item_new();
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1);
exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);
g_signal_connect(G_OBJECT(exit), "clicked",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
toolbar = gtk_toolbar_new();We create a new toolbar. We specify that the toobar buttons show only icons. No text.
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS)
new = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);We create a toolbar button from stock. The toolbar buttons are inserted into the toolbar by the gtk_toolbar_insert() function call.
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), new, -1);
sep = gtk_separator_tool_item_new();Here we insert a separator into the toolbar.
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1);
Figure: Toolbar
Undo redo
The following example demonstrates, how we can inactivate toolbar buttons on the toolbar. It is a common practice in GUI programming. For example the save button. If we save all changes of our document to the disk, the save button is inactivated in most text editors. This way the application indicates to the user, that all changes are already saved.#include <gtk/gtk.h>Our example creates undo and redo buttons from the GTK+ stock resources. After several clicks each of the buttons is inactivated. The buttons are grayed out.
#include <string.h>
void undo_redo(GtkWidget *widget, gpointer item)
{
static int count = 2;
const char *name = gtk_widget_get_name(widget);
if ( strcmp(name, "undo") ) {
count++;
} else {
count--;
}
if (count < 0) {
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
if (count > 5) {
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
}
int main( int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *toolbar;
GtkToolItem *undo;
GtkToolItem *redo;
GtkToolItem *sep;
GtkToolItem *exit;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
gtk_window_set_default_size(GTK_WINDOW(window), 250, 200);
gtk_window_set_title(GTK_WINDOW(window), "undoredo");
vbox = gtk_vbox_new(FALSE, 0);
gtk_container_add(GTK_CONTAINER(window), vbox);
toolbar = gtk_toolbar_new();
gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
gtk_container_set_border_width(GTK_CONTAINER(toolbar), 2);
undo = gtk_tool_button_new_from_stock(GTK_STOCK_UNDO);
gtk_widget_set_name(GTK_WIDGET(undo), "undo");
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), undo, -1);
redo = gtk_tool_button_new_from_stock(GTK_STOCK_REDO);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), redo, -1);
sep = gtk_separator_tool_item_new();
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), sep, -1);
exit = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exit, -1);
gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);
g_signal_connect(G_OBJECT(undo), "clicked",
G_CALLBACK(undo_redo), redo);
g_signal_connect(G_OBJECT(redo), "clicked",
G_CALLBACK(undo_redo), undo);
g_signal_connect(G_OBJECT(exit), "clicked",
G_CALLBACK(gtk_main_quit), NULL);
g_signal_connect_swapped(G_OBJECT(window), "destroy",
G_CALLBACK(gtk_main_quit), NULL);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
if (count < 0) {The gtk_widget_set_sensitive() function call is used to activate/inactivate the toolbar buttons.
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
if (count > 5) {
gtk_widget_set_sensitive(widget, FALSE);
gtk_widget_set_sensitive(item, TRUE);
}
Figure: Undo redo
In this chapter we have talked about menus and toolbars in GTK+.
No comments:
Post a Comment