gtk training

Post on 04-Jun-2018

238 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

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

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,

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);

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);

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);

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);

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

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.

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.

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

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.

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

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)

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.

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

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. */

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.");

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

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");

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

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.

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.

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.

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);

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

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

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

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

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);

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);

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);

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);

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.

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>

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

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 

top related