36
You can explicitly set the size and font of text to avoid overlap, but this is not advised in most cases. Accessibi lity options are provided for users with low vision. If you change their fonts, some users may not be able to read the text on the screen.  Another problem wit h using GtkFixed arises when your application is translated into other languages. A user interface may look great in English, but the displayed strings in other languages may cause display problems, because the width will not be constant. Furthermore, languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirrored with the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTable in this case. Finally, it can be quite a pain adding and removing widgets from your graphical interface when using a GtkFixed container. Changing the user interface will require you to reposition all of your widgets. If you have an application with a lot of widgets, this presents a long-term maintenance problem. On the other hand, you have tables, boxes, and various other automatically formatting containers. If you need to add or remove a widget from the user interface, it is as easy as adding or removing a cell. This makes maintenance much more efficient, which is something you should consider in large applications. 60 CHAPTER 3  CONTAINER WIDGETS Therefore, unless you know that none of the presented problems will plague your application, you should use variable-sized containers instead of GtkFixed. This container was presented only so you know it is available if a suitable situation arises. Even in suitable situations, flexible containers are almost always a better solution and are the proper way of doing things. Expanders The GtkExpander container can handle only one child. The child can be shown or hidden by clicking the triangle to the left of the expander’s label. A before -and-after screenshot of this action can be viewed in Figure 3-7. Figure 3-7. A GtkExpander container Listing 3-6 was used to create Figure 3-7. The example introduces you to the most important GtkExpander methods. Listing 3-6. Showing and Hiding Widgets (expanders.c) #include <gtk/gtk.h> int main (int argc, char *argv[]) { GtkWidget *window, *expander, *label; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVE L); gtk_window_set_tit le (GTK_WINDOW (window), "Expander"); gtk_container_set_b order_width (GTK_CONTAINER (window), 10); gtk_widget_set_siz e_request (window, 200, 100); expander = gtk_expander_new _with_mnemonic ("Click _Me For More!"); label = gtk_label_new ("Hide me or show me,\nthat is your choice."); CHAPTER 3  CONTAINER WIDGETS 61 gtk_container_add (GTK_CONTAIN ER (expander), label); gtk_expander_set_ex panded (GTK_EXPANDER (expander), TRUE); gtk_container_add (GTK_CONTAINE R (window), expander); gtk_widget_show_all (window); gtk_main (); return 0; } Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If you place an underscore in the initialization string of this function, a keyboard accelerator will be created. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widget will be activated. Activating a GtkExpander widget will cause it to be expanded or retracted depending on its current state. Tip Mnemonics are available in almost every widget that displays a label. Where available, you s hould always use this feature, because some users prefer to navigate through applications with the keyboard. If you wish to include an underscore character in the expander label, you should prefix it with a second underscore. If you do not want to take advantage of the mnemonic feature, you can use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, but providing mnemonics as an option to the user is always a good idea. In normal expander

Gtk Training

Embed Size (px)

Citation preview

Page 1: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 1/36

You can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirrored

with the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)

#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expander

Page 2: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 2/36

labels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().

void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. An

example of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detached

In Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");

gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,

Page 3: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 3/36

GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.

void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){

GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);

Page 4: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 4/36

gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,

GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTER

You can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languages

may cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presented

only so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);

Page 5: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 5/36

gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If you

place an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghost

is placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);

Page 6: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 6/36

gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;

}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge with

gtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.

• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);

Page 7: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 7/36

notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",

G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */

static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTER

You can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander container

Page 8: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 8/36

Listing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)

#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;

}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only contain

one child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removed

from the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.

Page 9: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 9/36

Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);

gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edge

is where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.

Page 10: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 10/36

Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,

char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");

/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;

}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTER

You can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition all

Page 11: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 11/36

of your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,

char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);

gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expander

labels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.

Page 12: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 12/36

void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.

When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);

gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the same

Page 13: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 13/36

position as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.

• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>

static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");

child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)

Page 14: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 14/36

gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)

#include <gtk/gtk.h>int main (int argc,

char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.

Page 15: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 15/36

If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()

to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.

When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of the

Page 16: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 16/36

handle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edge

is where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.

• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>

static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */

Page 17: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 17/36

gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;

}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");

Page 18: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 18/36

CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;

}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removed

from the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[])

{GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and

Page 19: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 19/36

* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);

gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edge

is where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.

• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)

#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");

Page 20: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 20/36

gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");

/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;

}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander container

Page 21: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 21/36

Listing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)

#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;

}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only contain

one child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removed

from the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.

Page 22: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 22/36

Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);

gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edge

is where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.

Page 23: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 23/36

Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,

char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");

/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;

}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languagesmay cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.

Page 24: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 24/36

On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presented

only so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;

}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only contain

one child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);

Page 25: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 25/36

62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, they

will be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);

gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge withgtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

Page 26: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 26/36

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.

• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,

char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");

/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);else

Page 27: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 27/36

gtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languages

may cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presented

only so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){

GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If youplace an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, you

Page 28: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 28/36

can use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpander

widget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghostis placed where the widget was originally located. If there are other widgets in the window, they

will be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)

#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side with

Page 29: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 29/36

GTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge with

gtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.

• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pages

When creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,

char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);

Page 30: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 30/36

gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */

static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languages

may cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presented

only so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);

Page 31: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 31/36

gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If you

place an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghost

is placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);

Page 32: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 32/36

gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;

}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge with

gtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.

• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widgetfor each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);

Page 33: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 33/36

notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",

G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */

static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTERYou can explicitly set the size and font of text to avoid overlap, but this is not advised inmost cases. Accessibility options are provided for users with low vision. If you change theirfonts, some users may not be able to read the text on the screen.

 Another problem with using GtkFixed arises when your application is translated into otherlanguages. A user interface may look great in English, but the displayed strings in other languages

may cause display problems, because the width will not be constant. Furthermore,languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirroredwith the GtkFixed widget. It is best to use a variable-sized container such as GtkBox or GtkTablein this case.Finally, it can be quite a pain adding and removing widgets from your graphical interfacewhen using a GtkFixed container. Changing the user interface will require you to reposition allof your widgets. If you have an application with a lot of widgets, this presents a long-termmaintenance problem.On the other hand, you have tables, boxes, and various other automatically formattingcontainers. If you need to add or remove a widget from the user interface, it is as easy as addingor removing a cell. This makes maintenance much more efficient, which is something youshould consider in large applications.60 CHAPTER 3■ CONTAINER WIDGETS

Therefore, unless you know that none of the presented problems will plague your application,you should use variable-sized containers instead of GtkFixed. This container was presentedonly so you know it is available if a suitable situation arises. Even in suitable situations, flexiblecontainers are almost always a better solution and are the proper way of doing things.

ExpandersThe GtkExpander container can handle only one child. The child can be shown or hidden byclicking the triangle to the left of the expander’s label. A before-and-after screenshot of thisaction can be viewed in Figure 3-7.Figure 3-7. A GtkExpander containerListing 3-6 was used to create Figure 3-7. The example introduces you to the most importantGtkExpander methods.

Page 34: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 34/36

Listing 3-6. Showing and Hiding Widgets (expanders.c)#include <gtk/gtk.h>int main (int argc,char *argv[]){GtkWidget *window, *expander, *label;gtk_init (&argc, &argv);

window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Expander");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);expander = gtk_expander_new_with_mnemonic ("Click _Me For More!");label = gtk_label_new ("Hide me or show me,\nthat is your choice.");CHAPTER 3■ CONTAINER WIDGETS 61

gtk_container_add (GTK_CONTAINER (expander), label);gtk_expander_set_expanded (GTK_EXPANDER (expander), TRUE);gtk_container_add (GTK_CONTAINER (window), expander);gtk_widget_show_all (window);gtk_main ();return 0;}Listing 3-6 uses gtk_expander_new_with_mnemonic() to initialize the GtkExpander. If you

place an underscore in the initialization string of this function, a keyboard accelerator will becreated. For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widgetwill be activated. Activating a GtkExpander widget will cause it to be expanded or retracteddepending on its current state.

■Tip Mnemonics are available in almost every widget that displays a label. Where available, you should

always use this feature, because some users prefer to navigate through applications with the keyboard.If you wish to include an underscore character in the expander label, you should prefix itwith a second underscore. If you do not want to take advantage of the mnemonic feature, youcan use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, butproviding mnemonics as an option to the user is always a good idea. In normal expanderlabels, underscore characters will not be parsed but will be treated as just another character.The GtkExpander widget itself is derived from GtkBin, which means that it can only containone child. As with other containers that hold one child, you need to use gtk_container_add()to add the child widget.

In Listing 3-6, I wanted the child widget to be visible by default, so I set the GtkExpanderwidget to be expanded. The child widget of a GtkExpander container can be shown or hidden bycalling gtk_expander_set_expanded().void gtk_expander_set_expanded (GtkExpander *expander,gboolean expanded);By default, GTK+ does not add any spacing between the expander label and the child widget.To add pixels of spacing, you can use gtk_expander_set_spacing() to add padding.void gtk_expander_set_spacing (GtkExpander *expander,gint spacing);62 CHAPTER 3■ CONTAINER WIDGETS

Handle BoxesThe GtkHandleBox widget is another type of GtkBin container that allows its child to be removedfrom the parent window by dragging it with the mouse.When removed, the child is placed in its own window that is without decorations. A ghost

is placed where the widget was originally located. If there are other widgets in the window, theywill be resized to fill the void of space if possible.This widget is most commonly used to contain toolbars and other toolkit displays. Anexample of a GtkHandleBox widget is shown in Figure 3-8. It shows the handle box attached tothe window and then removed. The handle box can be reattached by aligning it with the originallocation.Figure 3-8. A handle box attached and then detachedIn Listing 3-7, we create a GtkHandleBox widget that contains a GtkLabel child. The exampleshows all of the properties available to you through the GtkHandleBox class.Listing 3-7. Detachable Widgets (handleboxes.c)#include <gtk/gtk.h>

Page 35: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 35/36

int main (int argc,char *argv[]){GtkWidget *window, *handle, *label;gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Handle Box");

gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 200, 100);CHAPTER 3■ CONTAINER WIDGETS 63

handle = gtk_handle_box_new ();label = gtk_label_new ("Detach Me");/* Add a shadow to the handle box, set the handle position on the left and* set the snap edge to the top of the widget. */gtk_handle_box_set_shadow_type (GTK_HANDLE_BOX (handle), GTK_SHADOW_IN);gtk_handle_box_set_handle_position (GTK_HANDLE_BOX (handle), GTK_POS_LEFT);gtk_handle_box_set_snap_edge (GTK_HANDLE_BOX (handle), GTK_POS_TOP);gtk_container_add (GTK_CONTAINER (handle), label);gtk_container_add (GTK_CONTAINER (window), handle);gtk_widget_show_all (window);gtk_main ();return 0;

}When you create a GtkHandleBox widget, you need to decide where the handle and thesnap edge will be placed. The handle is the area on the side of the child widget that you grabonto in order to detach the GtkHandleBox child from its parent. When the handle box isdetached from the parent, a slim ghost is drawn in the original location.The function gtk_handle_box_set_handle_position() is used to set the position of thehandle. The GtkPositionType enumeration provides four options for the placement of the handle.By default, the handle position is set to GTK_POS_LEFT, but you can place it on any side withGTK_POS_RIGHT, GTK_POS_TOP, or GTK_POS_BOTTOM.void gtk_handle_box_set_handle_position (GtkHandleBox *handle_box,GtkPositionType position);Based on the handle position, GTK+ chooses the position for the snap edge, which iswhere the handle box must realign itself for it to be reattached to its parent. The snap edgeis where the ghost will appear after detachment.You can specify a new GtkPositionType value for the snap edge with

gtk_handle_box_set_snap_edge(). It is important for you to pay attention to whereyou place the snap edge with respect to the handle to avoid confusing the user.void gtk_handle_box_set_snap_edge (GtkHandleBox *handle_box,GtkPositionType position);For example, if the handle box is at the top of a GtkVBox widget and the handle is on the leftside, you should set the snap edge position as GTK_POS_TOP. This way, the ghost is in the sameposition as the snap edge without the need for resizing.64 CHAPTER 3■ CONTAINER WIDGETS

GtkHandleBox also provides gtk_handle_box_set_shadow_type(), which allows you to setthe type of border to place around the child widget. Values for the GtkShadowType enumerationfollow.• GTK_SHADOW_NONE: No border will be placed around the child.• GTK_SHADOW_IN: The border will be skewed inwards.• GTK_SHADOW_OUT: The border will be skewed outwards, like a button.• GTK_SHADOW_ETCHED_IN: The border will have a sunken 3-D appearance.• GTK_SHADOW_ETCHED_OUT: The border will have a raised 3-D appearance.

NotebooksThe GtkNotebook widget organizes child widgets into a number of pages. The user can switchbetween these pages by clicking the tabs that appear along one edge of the widget.You are able to specify the location of the tabs, although they appear along the top bydefault. You can also hide the tabs altogether. Figure 3-9 shows a GtkNotebook widget with twotabs that was created with the code in Listing 3-8.Figure 3-9. A notebook container with two pagesWhen creating a notebook container, you must specify a tab label widget and a child widget

Page 36: Gtk Training

8/13/2019 Gtk Training

http://slidepdf.com/reader/full/gtk-training 36/36

for each tab. Tabs can be added to the front or back, inserted, reordered, and removed.Listing 3-8. Container with Multiple Pages (notebooks.c)#include <gtk/gtk.h>static void switch_page (GtkButton*, GtkNotebook*);int main (int argc,char *argv[]){

GtkWidget *window, *notebook;GtkWidget *label1, *label2, *child1, *child2;CHAPTER 3■ CONTAINER WIDGETS 65

gtk_init (&argc, &argv);window = gtk_window_new (GTK_WINDOW_TOPLEVEL);gtk_window_set_title (GTK_WINDOW (window), "Notebook");gtk_container_set_border_width (GTK_CONTAINER (window), 10);gtk_widget_set_size_request (window, 250, 100);notebook = gtk_notebook_new ();label1 = gtk_label_new ("Page One");label2 = gtk_label_new ("Page Two");child1 = gtk_label_new ("Go to page 2 to find the answer.");child2 = gtk_label_new ("Go to page 1 to find the answer.");/* Notice that two widgets were connected to the same callback function! */g_signal_connect (G_OBJECT (child1), "clicked",

G_CALLBACK (switch_page),(gpointer) notebook);g_signal_connect (G_OBJECT (child2), "clicked",G_CALLBACK (switch_page),(gpointer) notebook);/* Append to pages to the notebook container. */gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child1, label1);gtk_notebook_append_page (GTK_NOTEBOOK (notebook), child2, label2);gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_BOTTOM);gtk_container_add (GTK_CONTAINER (window), notebook);gtk_widget_show_all (window);gtk_main ();return 0;}/* Switch to the next or previous GtkNotebook page. */

static voidswitch_page (GtkButton *button,GtkNotebook *notebook){gint page = gtk_notebook_get_current_page (notebook);if (page == 0)gtk_notebook_set_current_page (notebook, 1);elsegtk_notebook_set_current_page (notebook, 0);}66 CHAPTER