3.6 Data Entry Widgets


3.6 Data Entry Widgets

GTK+ has a number of basic data entry widgets:

  • GtkOptionMenu ( GTK_TYPE_OPTION ): Functionally, an option menu is the same as a group of radio buttons , but you should use them only under certain circumstances:

    • When there just isn't enough space for radio buttons.

    • When the number of items and labels can change.

    • For a logical progression of items (such as days of the week).

    However, if there are more than ten items, you should use a list instead (see Section 3.11).

  • GtkEntry ( GTK_TYPE_ENTRY ): An entry box is a single-line widget for entering a short bit of text. Use this type of entry box when you don't have any other way to represent data. If you need an entry box with history features, have a look at the derived class GnomeEntry in Section 4.3.4. If there are several sensible default options for the widget's state, consider the combo box; for numbers , use a slider or spin button.

  • GtkCombo ( GTK_TYPE_COMBO ): is a cross between an entry box and an option menu. You can enter a short line of text into a box, but you can also place common items into an attached menu for quick access. Don't write-protect a combo box's entry box to create a menu ” this is a popular tactic on other platforms, but GTK+ has option menus for this purpose.

  • GtkScale ( GTK_TYPE_SCALE ): Slider widgets allow you to pick a value within a certain range. They work well for relative settings ("a little louder," for example) and other types of input where specifying a precise value isn't terribly important.

    GtkScale is an abstract class; you'll use GtkHScale ( GTK_TYPE_HSCALE ) and GtkVScale for horizontal and vertical sliders in your actual implementations .

  • GtkSpinButton ( GTK_TYPE_SPIN_BUTTON ): Spin buttons allow the user to enter a precise numeric value that may or may not have particular bounds. The widget contains a box with a number and two buttons to increment and decrement the number by a certain amount.

The example you're about to see demonstrates all of these widgets. To make this interesting, the values of the two sliders and the spin button are linked; when you change one, the other two automatically change (the MVC lingo for this is that the widgets show different views ; see Section 3.11 for more information). Figure 3.9 shows the application.

click to expand
Figure 3.9: Option menu, entry box, combo box, spin button, and sliders.

The program starts with the standard event handlers for the main window. It also has a macro definition indicating the number of widgets in a table for the overall window layout:

 /* -*-coding: utf-8;-*- */ /* dataentry.c -- basic data entry widgets */ #include <gtk/gtk.h> /* usual event handlers */ gint delete_event(GtkWidget *widget, GdkEvent event, gpointer data) {   return FALSE; } void end_program(GtkWidget *widget, gpointer data) {   gtk_main_quit(); } #define NUM_WIDGETS 5 

The definitions for all of the entry widgets follow. The option menu, combo button, and slider require auxiliary data structures.

 int main(int argc, char **argv) {   GtkWindow *window;   GtkTable *table;   GtkOptionMenu *option_menu;   GtkEntry *entry_box;   GtkCombo *combo_box;   GtkSpinButton *spin_button;   GtkHScale *h_slider;   GtkVScale *v_slider;   GtkMenu *names_menu;        /* for option menu */   GList *combo_list = NULL;   /* for combo button */   GtkAdjustment *adjust;      /* for sliders and spin button */   GtkWidget *mnemo;   /* initialize GTK+, create window */   gtk_init(&argc, &argv);   window = g_object_new(GTK_TYPE_WINDOW,                         "title", "Data Entry Widgets",                         "border-width", 12,                         "default-width", 400,                         NULL);   /* connect standard window handlers */   g_signal_connect(window, "delete_event", G_CALLBACK(delete_event), NULL);   g_signal_connect(window, "destroy", G_CALLBACK(end_program), NULL); 

Sliders and spin buttons require a GtkAdjustment object so that they know the range of values that they may represent. This object also holds the value for the slider or spin button; see Section 3.6.4 for more information on these objects, including information on how to access the value.

 /* define the range for the slider widgets, spin button */   adjust = GTK_ADJUSTMENT(gtk_adjustment_new(1.0,    /* initial value */                                              -100.0, /* minimum */                                              100.0,  /* maximum */                                              0.5,    /* step */                                              10.0,   /* page step*/                                              0.0));  /* page size */ 

Now that you have adjust , it's easy to create the horizontal and vertical slider widgets. Because both sliders use adjust for their adjustment properties, when you change one of these widgets, the other will also react . Section 3.6.5 details the GtkScale properties.

 /* create vertical slider */   v_slider = g_object_new(GTK_TYPE_VSCALE, "adjustment", adjust, NULL);   /* create horizontal slider */   h_slider = g_object_new(GTK_TYPE_HSCALE, "adjustment", adjust, NULL); 

To create a GtkOptionMenu widget, you must create the menu that goes inside the widget. The following code creates names_menu with three items.

 /* create and define a menu */   names_menu = g_object_new(GTK_TYPE_MENU, NULL);   gtk_menu_shell_append(GTK_MENU_SHELL(names_menu),                         gtk_menu_item_new_with_label("Harrisburg"));   gtk_menu_shell_append(GTK_MENU_SHELL(names_menu),                         gtk_menu_item_new_with_label("Pittsburgh"));   gtk_menu_shell_append(GTK_MENU_SHELL(names_menu),                         gtk_menu_item_new_with_label("Hollidaysburg")); 

With the menu in hand, you can create the GtkOptionMenu widget with a menu property. See Section 3.6.1 for more information on option menus.

 /* create an options menu, using the menu above */   option_menu = g_object_new(GTK_TYPE_OPTION_MENU, "menu", names_menu, NULL); 

You can set the current element in the option menu:

 /* set index 1 as default */   gtk_option_menu_set_history(option_menu, 1); 

Entry box widgets are simple; their text property is the current text inside the widget. Section 3.6.2 is dedicated to entry boxes.

 /* create an entry box */   entry_box = g_object_new(GTK_TYPE_ENTRY, "text", "type something here", NULL); 

A combo box (see also Section 3.6.3) is a little trickier than an option menu because you may frequently change its default entries. Combo boxes take a list of strings as default entries.

 /* create a list of names */   combo_list = g_list_append(combo_list, "Townsville");   combo_list = g_list_append(combo_list, "Pleasantville");   combo_list = g_list_append(combo_list, "Springfield");   combo_list = g_list_append(combo_list, "Smallville");   /* create a combo box */   combo_box = g_object_new(GTK_TYPE_COMBO, NULL);   /* add the list of names to the combo box */   gtk_combo_set_popdown_strings(combo_box, combo_list); 

There is actually an entry box inside each combo box; its text property represents the combo box's value.

 /* set a default entry in combo box */   g_object_set(combo_box->entry, "text", "Alphaville", NULL); 

After you feed the list of strings to the combo box, you no longer need the list data structure.

 /* list structure no longer necessary */   g_list_free(combo_list); 

When you create a spin button, you need a GtkAdjustment object for the adjustment property, just as you did for sliders. More detail on spin buttons is in Section 3.6.6.

 /* spin button */   spin_button = g_object_new(GTK_TYPE_SPIN_BUTTON,                              "adjustment", adjust,                              "digits", 1,                              "value", 42.0,                              NULL); 

Creating the table and putting the widgets into the table is primarily an exercise in typing. However, you should take a look at the mnemonic-widget property in each widget's label; it enables a hot key for the input focus to go straight to the label's widget. Combo boxes are a little different in this respect. Typically, you don't want the input focus on the combo box, but rather, the entry box inside.

Note  

This code uses a macro to save some typing. If you were writing a real program, you would probably make this into a function. Not only would a function offer more flexibility, but the resulting object code would be smaller. Here, you can see the result of the macro expansion alongside the macro calls.

 table = g_object_new(GTK_TYPE_TABLE,                        "n-rows", NUM_WIDGETS,                        "n-columns", 3,                        "row-spacing", 6,                        NULL);   /* this macro packs one of the data entry widgets into      the table, along with a label */   /* if the widget is a combo box, set its mnemonic to      the entry box inside the combo */ #define PACK_IN_TABLE(widget, label, row_num)                  \     mnemo = GTK_WIDGET(widget);                                \     if (GTK_IS_COMBO(widget))                                  \       { mnemo = GTK_COMBO(widget)->entry; }                    \     gtk_table_attach(table,                                    \                      g_object_new(GTK_TYPE_LABEL,              \                                   "label", label,              \                                   "use-underline", TRUE,       \                                   "mnemonic-widget", mnemo,    \                                   "xalign", 1.0,               \                                   "justify", GTK_JUSTIFY_RIGHT,\                                   NULL),                       \                      0, 1, row_num, row_num+1,                 \                      GTK_EXPANDGTK_FILL, 0, 0, 0);            \                                                                \     gtk_table_attach(table, \                      g_object_new(GTK_TYPE_ALIGNMENT,          \                                   "xalign", 0.0,               \                                   "child", widget,             \                                   NULL),                       \                      1, 2, row_num, row_num+1,                 \                      GTK_EXPANDGTK_FILL, 0, 6, 0);   /* pack the widgets and their labels into the table */   PACK_IN_TABLE(option_menu, "_Option menu:",      0)   PACK_IN_TABLE(entry_box,   "_Entry box:",        1)   PACK_IN_TABLE(combo_box,   "_Combo box:",        2)   PACK_IN_TABLE(spin_button, "_Spin button:",      3)   PACK_IN_TABLE(h_slider,    "_Horizonal slider:", 4) 

The preceding code placed all of the widgets except the vertical slider into table rows. The vertical slider would look absurd inside a row, so it takes up an entire column instead.

 /* pack the vertical slider and its label into the table */   gtk_table_attach(table,                    g_object_new(GTK_TYPE_LABEL,                                 "label", "_Vertical slider:",                                 "use_underline", TRUE,                                 "mnemonic-widget", v_slider,                                 NULL),                    2, 3, 0, 1,                    GTK_SHRINK, 0, 6, 0);   gtk_table_attach(table, GTK_WIDGET(v_slider),                    2, 3, 1, 5,                    GTK_SHRINK,                    GTK_EXPANDGTK_FILL, 0, 0);   /* pack table into window, show everything, begin main loop */   gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(table));   gtk_widget_show_all(GTK_WIDGET(window));   gtk_main();   return 0; } 

There are three specialized data entry widgets that you may need from time to time:

  • Color picker: This large, powerful widget lets the user choose a color with the help of a color wheel, sliders, and palette. GtkColorSelection is the base widget, but there is dialog box version: GtkColorSelectionDialog . See Section 3.6.7 for more information on these widgets.

  • Font chooser: This is the font equivalent of the color picker. Section 3.6.8 covers GtkFontSelection and its dialog box cousin, GtkFontSelectionDialog .

  • File browser: The average user frequently encounters this familiar list of directories and files. This widget comes only as a dialog box: GtkFileSelection . Section 3.6.9 shows you how to work with file browsers.

Note  

GNOME offers additional interface widgets. If you need a small button of a current color that activates a color chooser on a mouse click, have a look at GnomeColorPicker in Section 4.3.7. For fonts and files, the equivalent classes are GnomeFontPicker (Section 4.3.6) and GnomeFileEntry (Section 4.3.5).

3.6.1 Option Menus

An option menu ( GtkOptionMenu , type identifier GTK_TYPE_OPTION_MENU ) is a button that calls a true GtkMenu widget when clicked, and therefore, you need to know how to create menu objects. The example in the previous section should give you a fairly clear idea of how to do this; Section 4.3.1 details the complete workings of GTK+ menus.

Note  

Use only regular menu items in an options menu. Separators, submenus, and key combinations are counterproductive.

Normal menus typically call commands, but an option menu picks an element from a list. You can set the current element with

 gtk_option_menu_set_history(  menu  ,  i  ) 

where menu is the option menu object, and i is the index of the element (the first element is at index 0). To retrieve the menu's current element index, use

 gtk_option_menu_get_history(  menu  ) 

The return value is gint ; -1 means that there are no items in the option menu.

Option menus have a changed signal that GTK+ emits this when the user selects something in a menu. Use a prototype like this for your signal handler:

 void handler(GtkOptionMenu *option_menu, gpointer data); 

3.6.2 Entry Boxes

There are few widgets as easy to operate as an entry box (class GtkEntry , type GTK_TYPE_ENTRY ). After you create and pack an entry widget, you can set and fetch the string with its text property.

Once you start to work with entry boxes, you'll quickly find that they can do a number of interesting things. For example, when you right-click the box, a small context menu appears with Cut/Copy/Paste and input mode items.

Other GtkEntry properties include the following:

  • cursor-position ( gint , read-only): The current position of the cursor in the box. A value of 0 means that the cursor is in front of the first character, 1 means that it is in front of the second character, and so on.

  • selection-bound ( gint , read-only): If the user has selected something in the entry box, this is the end of the selection.

  • editable ( gboolean ): If FALSE , the user may not change the text inside the box.

  • max-length ( gint ): Maximum length of the string inside the entry box; 0 specifies no limit.

  • visibility ( gboolean ): If you set this property to FALSE , the real characters won't show up in the widget. There will be a substitute (see the next property). You can use this feature for password entry.

  • invisible-char ( guint ): The character to substitute in conjunction with the visibility feature (the default is an asterisk).

  • has-frame ( gboolean ): If TRUE , a relief frame appears around the box.

  • activates-default ( gboolean ): If the entry box is part of a dialog, a TRUE value here means that pressing ENTER in the entry box also activates the default button in the dialog box.

  • width-chars ( gint ): The width of the entry box in characters.

  • scroll-offset ( gint , read-only): If the user enters so much text into the box that scrolling is necessary, this property holds the number of pixels that the box scrolled.

Although the cursor-position and selection-bound properties are read-only, you can still manipulate the cursor position and selection though the GtkEditable ( GTK_TYPE_EDITABLE ) interface. Here are the methods in the interface:

  • void gtk_editable_insert_text(GtkEditable * widget , const gchar * text , gint length, gint * position )

    Inserts text into widget at index position . The length value indicates the length of the text in bytes , not characters. Note that position is a pointer (or address); this function writes the new cursor position back into this location.

  • void gtk_editable_delete_text(GtkEditable * widget , gint begin , gint end )

    Removes the characters from index begin up to (but not including) end from widget . If end is negative, this function removes all characters from begin to the end of the buffer.

  • gchar *gtk_editable_get_chars(GtkEditable * widget , gint begin , gint end )

    Returns the string between begin and end .

  • void gtk_editable_cut_clipboard(GtkEditable * widget )

    Removes the currently selected text in widget and places it in the clipboard.

  • void gtk_editable_copy_clipboard(GtkEditable * widget )

    Copies the currently selected text in widget in the clipboard.

  • void gtk_editable_paste_clipboard(GtkEditable * widget )

    Copies the clipboard's content into widget at its current cursor position.

  • void gtk_editable_delete_clipboard(GtkEditable * widget )

    Removes the currently selected text in widget (does not save a copy).

The GtkEditable interface also defines these signals (and handler prototypes ):

  • changed

    void handler(GtkEditable *widget, gpointer data)

    Emitted when the user changes something inside the text.

  • insert-text

    void handler(GtkEditable *widget, gchar *text, gchar *length, gint *position, gpointer data)

    Emitted when the user inserts text. The new text is at text , length bytes long. The position value is the new location of the cursor. You can attach a handler to this signal if you want to control if and when text is inserted.

  • delete-text

    void handler(GtkEditable *widget, gint begin, gint end, gpointer data)

    Emitted when the user removes text between begin and end .

GtkEntry has one signal of its own: activate . GTK+ emits this when the user activates the entry box (for example, by pressing ENTER). Its prototype is

 void handler(GtkEntry *widget, gpointer data) 

3.6.3 Combo Boxes

GtkCombo class widgets ( GTK_TYPE_COMBO ) include an entry pointer in their instance structures, so they can also use all characteristics of the GtkEntry class. In the example in Section 3.6, you saw how to access this embedded object with combo ->entry .

Combo boxes add the functionality of choosing from a number of default strings through lists. To set these defaults, create a GList of strings and call

 gtk_combo_set_popdown_strings(  combo  ,  list  ) 

where combo is the combo box, and list is the set of strings. The combo box sets the value in its entry box to the first string in the list. The example in the previous section also illustrates how you can get a different default: Set combo ->entry 's text property after you initialize the defaults with the function described earlier.

gtk_combo_set_popdown_strings() writes the first list argument into the combo entry box.

Combo box widgets have these gboolean properties:

  • enable-arrow-keys : If TRUE , the user can navigate through the default list with the up and down arrow keys.

  • enable-arrow-always : If FALSE , the user can navigate through the default list with the arrow keys only when the current content of the box is one of the defaults.

  • case-sensitive : If FALSE , the current content of the box can match a default even if it uses different case characters (this property works in conjunction with the preceding property).

  • allow-empty : If FALSE , the user may not leave the box in an empty state.

Note  

GtkCombo can do much more. For example, the item list can accept any kind of widget, and you can strictly control the text in the box. However, all of this detracts from its intended use. If you want a list, use a list box (see Section 3.11), and if you want an option menu, use an option menu (see Section 3.6.1).

3.6.4 Adjustment Objects

A GtkAdjustment (class type GTK_TYPE_ADJUSTMENT ) object works with a widget to help store the widget's represented value and give the widget some hints on appearance. Sliders, spin buttons, and scrollbars (see Section 3.9) typically work with GtkAdjustment objects.

To create an adjustment object, use

 GtkAdjustment *  adj  ; adj = gtk_adjustment_new(  initial  ,  lower  ,  upper  ,  step_increment  ,  page_increment  ,  page_size  ); 

All of the parameters are gdouble floating-point numbers:

  • initial is adj 's initial value.

  • lower is the lower bound of adj 's value.

  • upper is the upper bound of adj 's value.

  • step_increment is a small step; when you drag a slider or click the spin button's arrow, adj 's value changes by at least this much.

  • page_increment is a big step; a click in the trough of a slider changes adj 's value by this much.

  • page_size is the currently visible size of the page. This parameter is useful only for scrollbars; set this to 0 for sliders and spin buttons.

To set and retrieve the value of an adjustment object, use

 void gtk_adjustment_set_value(  object  ) 

and

 gdouble gtk_adjustment_get_value(  object  ) 

This object is essentially a data structure, and you can directly access its fields as they appear above (for example, adj ->upper ). However, if you change something, you should tell the attached widgets about the change with gtk_adjustment_changed( adj ) .

GTK+ emits two signals for adjustment objects: value-changed when the value in the object changes, and changed when one of its parameters changes. The handler prototype for both signals is

 void handler(GtkAdjustment *adjust, gpointer data) 

3.6.5 Slider Widgets

Sliders can be horizontal ( GtkHScale , GTK_TYPE_HSCALE ) or vertical ( GtkVScale , GTK_TYPE_VSCALE ). Their parent class is GtkScale , and all scale widgets include these properties:

  • adjustment ( GtkAdjustment * ): The range and value for the slider, as described in Section 3.6.4.

  • draw-value ( gboolean ): If TRUE , GTK+ shows the slider's value next to the slider. See the format-value signal described later in this section if you want fine control over the displayed value's format.

  • digits ( gint ): The number of digits to the right of the decimal point in the value display. The default is 1.

  • value-pos ( GtkPositionType ): Determines where the slider value display appears relative to the slider. Possible values are

    • GTK_POS_LEFT

    • GTK_POS_RIGHT

    • GTK_POS_TOP

    • GTK_POS_BOTTOM

Sliders belong to the parent class GtkRange (not to be confused with GtkAdjustment ); this is where adjustment comes from. There are two more properties:

  • update-policy (enumeration): Specifies how often the slider should update its GtkAdjustment value. The possible values are

    • GTK_UPDATE_CONTINUOUS : Update the value as soon as it changes; this is the default.

    • GTK_UPDATE_DISCONTINUOUS : Update the value when the user lets go of the slider.

    • GTK_UPDATE_DELAYED : If the user still has the mouse clicked down on the slider, update if there hasn't been any activity for a certain amount of time.

    The last two modes work well for sliders that require significant computation for a redisplay; one example is the saturation adjustment in Section 3.3.2's program.

  • inverted ( gboolean ): If TRUE , the slider reverses its lower and upper bound ends.

Sliders come with a format-value signal, using this handler prototype:

 gchar *handler(GtkScale *slider, gdouble number, gpointer data); 

GTK+ emits format-value to get a string to display as the new value when the user adjusts the slider; the number parameter is the new value. In your handler, allocate a new string and fill it out as you prefer. GTK+ frees this new memory when it is no longer needed. The program in Section 3.3.2 contains an example of a custom handler.

Note  

If you have a slider with a large range (a large integral range, in particular), GNOME Usability Guidelines say that you should include a spin button with the same GtkAdjustment value/range object to allow for fine control. You can pack the spin button at one end of the slider and set the slider's draw-value property to FALSE .

3.6.6 Spin Button Widgets

Spin buttons ( GtkSpinButton , GTK_TYPE_SPIN_BUTTON ) allow a user to adjust a value with arrow buttons; the user can also type a new value in the display, just as in an entry box. The programming interface resembles sliders in many respects. Spin button properties include the following:

  • adjustment ( GtkAdjustment * ): The range and value for the spin button, as described in Section 3.6.4.

  • climb-rate ( gdouble ): The rate at which the step increment grows when the user presses and holds the mouse button on the increment arrow. After every fifth increment with the mouse button down, the spin button adds this value to the step increment. The default is 0 (no acceleration).

  • digits ( gint ): The number of digits to the right of the decimal point in the value display. The default is 0.

  • snap-to- ticks ( gboolean ): If TRUE , the spin button rounds any typed-in value to the nearest increment. The default is FALSE .

  • wrap ( gboolean ): If TRUE , the spin button's value cycles around when the user clicks past an upper or lower bound. The default is FALSE .

  • update-policy ( GtkSpinButtonUpdatePolicy ): One of these two values:

    • GTK_UPDATE_ALWAYS : Change the spin button's value whenever the user types something into the box.

    • GTK_UPDATE_IF_VALID : Change the spin button's value if the user's input conforms to the range that the spin button can represent.

  • value ( gdouble ): The current value of the spin button. You can also access this through the spin button's associated GtkAdjustment object.

  • numeric ( gboolean ): If FALSE , you can enter nonnumeric characters into the spin button. This could be useful for hexadecimal values, but to do this, you will need to add handlers for the input and output signals (not covered in this book).

The spin button class is a subclass of GtkEntry (see Section 3.6.2) and therefore inherits all properties, methods, and signals from that class.

3.6.7 Color Chooser Widgets

GtkColorSelection (class type GTK_TYPE_COLOR_SELECTION ) is a color selection, complete with red-green-blue controls, hue-saturation-value controls, and a color sampler (see Figure 3.12 on page 173 for an example). After you create a color picker, it can go anywhere in a window. The color chooser's properties are as follows :

  • has-palette ( gboolean ): If TRUE , the chooser includes a palette alongside the other controls. The default is FALSE .

  • has-opacity-control ( gboolean ): If TRUE , the chooser includes a slider for the opacity (alpha channel). The default is FALSE .

  • current-color ( GdkColor ): The current color in the chooser. A GdkColor structure includes red , green , and blue fields, all guint16 .

  • current-alpha ( guint ): The current alpha channel value (0 is completely transparent; 65536 is opaque ).

Every time the user changes the color in the chooser, GTK+ emits a color-changed signal. The prototype for the handler is

 void handler(GtkColorSelection *  widget  , gpointer  data  ); 

Because this signal goes out even when the user drags a color across the color wheel, you need to think twice about doing serious computation based on the color. Use the function

 gtk_color_selection_is_adjusting(  chooser_widget  ) 

in your signal handler to see if the user is still adjusting chooser_widget . If the return value is TRUE , you may want to wait for a later handler invocation to do any computation. The example in Section 3.6.10 does this.

GtkColorSelectionDialog ( GTK_TYPE_COLOR_SELECTION_DIALOG ) is a complete color chooser inside a dialog box. However, because GnomeColorPicker (see Section 4.3.7) tends to handle these situations better, this book won't elaborate on the dialog box version of the color chooser.

3.6.8 Font Chooser Widgets

A GtkFontSelection ( GTK_TYPE_FONT_SELECTION ) widget, shown in Figure 3.10, allows the user to preview and choose fonts. There are two important properties, both gchararray strings:

  • font- name : The name of the currently selected font.

  • preview-text : The text at the bottom of the widget that demonstrates the currently selected font.

click to expand
Figure 3.10: GTK+ font chooser.

A font chooser doesn't have any important functions or signals. Therefore, you are responsible for creating the mechanism for determining what to do with the font selection. As with the color chooser, there is a dialog box version called GtkFontSelectionDialog ; however, because the GnomeFontPicker object in Section 4.3.6 is usually a better tool choice, there will be no further discussion of the font chooser dialog box in this book.

3.6.9 File Browsers

Unlike the color and font widgets, GtkFileSelection ( GTK_TYPE_FILE_SELECTION ) is available only as a separate dialog box, shown in Figure 3.11. Normally, you create the dialog box with a button or menu item signal handler. You must also provide additional signal handlers to decide what to do when the user clicks the OK and Cancel buttons. These buttons are the ok_button and cancel_button fields of the file selection object, so when you attach a signal handler to file_browser 's OK button, you can access the button with file_browser ->ok_button (an example of this appears in Section 3.6.10).

click to expand
Figure 3.11: GTK+ file browser.

Normally, you can select only a single file from a file browser; the full path -name of the file is a gchararray string in the browser's filename property.

However, you can enable multiple-file selection with the gboolean select-multiple property. Of course, if you want multiple files, you can no longer get the file through the simple filename property. Use

  files  = gtk_file_selection_get_selections(  file_browser  ); 

to get all of the filenames. The files value should have type gchararray * ; a NULL value indicates the last element in this array of strings. After you're finished with the filenames, use g_strfreev( files ) to free their memory.

Note  

All filenames that come from the browser are in the operating system's character encoding. If you want to put the name into a GTK+ widget, you should convert the name to UTF-8 with one of the functions in Section 1.4.4.

A final browser property is show-fileops ( gboolean ). If you set this to TRUE , three buttons for creating directories, removing files, and renaming files appear at the top of the file browser dialog box.

If you need a filename with a file selection button, consider using GnomeFileEntry , described in Section 4.3.5.

3.6.10 Chooser Examples

This section presents a sample program for the color chooser, font chooser, and file browser; see Figure 3.12 for the final product. The demonstration starts with the usual window signal handlers as well as a global declaration for the file browser dialog box:

 /* -*-coding: utf-8;-*- */ /* selections.c -- demonstrate selection widgets */ #include <gtk/gtk.h> GtkFileSelection *file_browser; /* standard handlers */ gint delete_event(GtkWidget *widget, GdkEvent event, gpointer data) {   return FALSE; } void end_program(GtkWidget *widget, gpointer data) {   gtk_main_quit(); } 
click to expand
Figure 3.12: Color, font, and file selection application.

This handler function is meant for the color chooser's color-changed signal. Notice how it does nothing if the user is still dragging something around on the widget.

 /* handler for "color-changed" signal, prints new color to console */ void print_color(GtkColorSelection *chooser, gpointer data) {   GdkColor color;   guint red, green, blue;   guint alpha;   /* if user is still adjusting the widget, do nothing */   if (!gtk_color_selection_is_adjusting(chooser))   {      g_object_get(chooser, "current-color", &color, NULL);      red = color.red;      green = color.green;      blue = color.blue;      g_object_get(chooser, "current-alpha", &alpha, NULL);      g_print("color chosen: R=%d, G=%d, B=%d, A=%d\n",              red, green, blue, alpha);   } } 

This handler displays the selection from a file browser after the user clicks the OK button. Its signal attachment is discussed later in this section.

 /* prints name file selected in file_browser */ void print_filename(GtkButton *button, gpointer data) {   gchar *filename;   g_object_get(file_browser, "filename", &filename, NULL);   g_print("file chosen: %s\n", filename);   g_free(filename); } 

Creating the file browser dialog box is a fairly straightforward task. You can see how to connect the print_filename() handler in the preceding code to the browser's OK button, as well as how to remove the window after the user clicks OK or Cancel.

 /* creates the file browser and attaches signals */ void make_file_dialog(GtkButton *button, gpointer data) {   file_browser = g_object_new(GTK_TYPE_FILE_SELECTION, NULL);   gtk_window_set_title(GTK_WINDOW(file_browser), "Select a File");   g_signal_connect(file_browser->ok_button,                    "clicked", G_CALLBACK(print_filename), NULL);   g_signal_connect_swapped(file_browser->ok_button,                            "clicked", G_CALLBACK(gtk_widget_destroy),                            file_browser);   g_signal_connect_swapped(file_browser->cancel_button,                            "clicked", G_CALLBACK(gtk_widget_destroy),                            file_browser);   gtk_widget_show(GTK_WIDGET(file_browser)); } 

The main program window uses a simple layout: All widgets will go into a single column with a VBox.

 int main(int argc, char **argv) {   GtkWindow *window;   GtkColorSelection *color_chooser;   GtkFontSelection *font_chooser;   GtkButton *file_browser_button;   GtkVBox *vbox;   GtkLabel *color_label, *font_label, *file_label;   /* initialize GTK+, create window */   gtk_init(&argc, &argv);   window = g_object_new(GTK_TYPE_WINDOW, "title", "Chooser Widgets", NULL);   /* attach standard handlers */   g_signal_connect(window, "delete_event", G_CALLBACK(delete_event), NULL);   g_signal_connect(window, "destroy", G_CALLBACK(end_program), NULL);   /* create vbox for main display */   vbox = g_object_new(GTK_TYPE_VBOX, "spacing", 6, "border-width", 12, NULL); 

Creating the color chooser is just like creating any simple widget. Every selection widget in this program has a label (for organization purposes).

 /* create a color chooser and label, pack them into a VBox */   color_label = g_object_new(GTK_TYPE_LABEL,                              "label", "<b>Color picker:</b>",                              "use-markup", TRUE,                              "xalign", 0.0,                              NULL);   color_chooser = g_object_new(GTK_TYPE_COLOR_SELECTION,                                "has-palette", TRUE,                                NULL); 

This code attaches the signal handler print_color() to print the selected color.

 /* add an event handler for when user picks a color */   g_signal_connect(color_chooser,                    "color-changed", G_CALLBACK(print_color), NULL); 

You don't need to do anything special to pack the color chooser, either. The single horizontal separator implemented here is for organizational purposes; you'll see more detail on separators in Section 3.7.

 gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(color_label));   gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(color_chooser));   gtk_box_pack_start_defaults(GTK_BOX(vbox),                               g_object_new(GTK_TYPE_HSEPARATOR, NULL)); 

The font chooser setup is nearly identical to that of the color chooser, but it does not have an event handler.

 /* create a font chooser and label, pack them into a VBox */   font_label = g_object_new(GTK_TYPE_LABEL,                             "label", "<b>Font chooser:</b>",                             "use-markup", TRUE,                             "xalign", 0.0,                             NULL);   font_chooser = g_object_new(GTK_TYPE_FONT_SELECTION, NULL);   gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(font_label));   gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(font_chooser)); 

Because the file browser is available only as a dialog box, you can't pack it into the main window. This program packs a button into the window that calls the file browser dialog box when clicked.

 /* create a file browser button and label, pack them into a VBox */   file_label = g_object_new(GTK_TYPE_LABEL,                             "label", "<b>Click for file browser:</b>",                             "use-markup", TRUE,                             "xalign", 0.0,                             NULL);   /* use a stock label/image for the button */   file_browser_button = g_object_new(GTK_TYPE_BUTTON,                                      "use-stock", TRUE,                                      "label", GTK_STOCK_OPEN,                                      NULL);   /* handler for creating file browser */   g_signal_connect(file_browser_button,                    "clicked", G_CALLBACK(make_file_dialog), NULL);   gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(file_label));   gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(file_browser_button));   /* pack VBox into window, show everything, start event loop */   gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(vbox));   gtk_widget_show_all(GTK_WIDGET(window));   gtk_main();   return 0; } 



The Official GNOME 2 Developers Guide
The Official GNOME 2 Developers Guide
ISBN: 1593270305
EAN: 2147483647
Year: 2004
Pages: 108

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net