apress foundations_of gtk plus development 2007 phần 2 pdf

44 327 0
apress foundations_of gtk plus development 2007 phần 2 pdf

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

7931ch03.fm Page 53 Wednesday, March 7, 2007 8:54 PM CHAPTER ■ CONTAINER WIDGETS resize shrink Result FALSE TRUE The widget will not resize itself to take up additional space available in the pane, but the user will be able to make it smaller than its size requisition FALSE FALSE The widget will not resize itself to take up additional space available in the pane, and the available space must be greater than or equal to the widget’s size requisition You can easily set the exact position of the resize bar with gtk_paned_set_position() The position is calculated in pixels with respect to the top or left side of the container If you set the position of the bar to zero, it will be moved all the way to the top or left if the widget allows shrinking void gtk_paned_set_position (GtkPaned *paned, gint position); Most applications will want to remember the position of the resize bar, so it can be restored to the same location when the user next loads the application The current position of the resize bar can be retrieved with gtk_paned_get_position() gint gtk_paned_get_position (GtkPaned *paned); GtkPaned provides multiple signals, but one of the most useful is move-handle, which will tell you when the resizing bar has been moved If you want to remember the position of the resize bar, this will tell you when you need to retrieve a new value A full list of GtkPaned signals can be found in Appendix B Tables So far, all of the layout container widgets I have covered only allow children to be packed in one dimension The GtkTable widget, however, allows you to pack children in two-dimensional space One advantage of using the GtkTable widget over using multiple GtkHBox and GtkVBox widgets is that children in adjacent rows and columns are automatically aligned with each other, which is not the case with boxes within boxes However, this is also a disadvantage, because you will not always want everything to be lined up in this way Figure 3-4 shows a simple table that contains three widgets Notice that the single label spans two columns This illustrates the fact that tables allow one widget to span multiple columns and/or rows as long as the region is rectangular Figure 3-4 A table containing a label widget that spans multiple columns 53 7931ch03.fm Page 54 Wednesday, March 7, 2007 8:54 PM 54 CHAPTER ■ CONTAINER WIDGETS Listing 3-4 creates the GtkTable widget shown in Figure 3-4, inserting two GtkLabel widgets and a GtkEntry widget into the two-by-two area (you will learn how to use the GtkEntry widget in Chapter 4, but this gives you a taste of what is to come) Listing 3-4 GtkTable Displaying Name (tables.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *table, *label, *label2, *name; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Tables"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 150, 100); table = gtk_table_new (2, 2, TRUE); label = gtk_label_new ("Enter the following information "); label2 = gtk_label_new ("Name: "); name = gtk_entry_new (); /* Attach the two labels and entry widget to their parent container */ gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, GTK_EXPAND, GTK_SHRINK, 0, 0); gtk_table_attach (GTK_TABLE (table), label2, 0, 1, 1, 2, GTK_EXPAND, GTK_SHRINK, 0, 0); gtk_table_attach (GTK_TABLE (table), name, 1, 2, 1, 2, GTK_EXPAND, GTK_SHRINK, 0, 0); /* Add five pixels of spacing between every row and every column */ gtk_table_set_row_spacings (GTK_TABLE (table), 5); gtk_table_set_col_spacings (GTK_TABLE (table), 5); gtk_container_add (GTK_CONTAINER (window), table); gtk_widget_show_all (window); gtk_main (); return 0; } 7931ch03.fm Page 55 Wednesday, March 7, 2007 8:54 PM CHAPTER ■ CONTAINER WIDGETS Table Packing When creating a table with gtk_table_new(), you must specify the number of columns, the number of rows, and whether table cells should be homogeneous GtkWidget* gtk_table_new (guint rows, guint columns, gboolean homogeneous); The number of columns and rows can be changed after creating the table with gtk_table_resize(), but you should use the correct numbers initially, if possible, to avoid confusion on the part of the user You not want to get in the habit of liberally changing user interfaces when it is not completely necessary void gtk_table_resize (GtkTable *table, guint rows, guint columns); The function gtk_table_set_homogeneous() can also be used to reset the homogeneous property after creation, but you should use the desired value initially here as well The user should have control of resizing after the initial user interface is set void gtk_table_set_homogeneous (GtkTable *table, gboolean homogeneous); Packing a new widget is performed with gtk_table_attach() The second parameter, child, refers to the child widget that you are adding to the table void gtk_table_attach (GtkTable *table, GtkWidget *child, guint left, guint right, guint top, guint bottom, GtkAttachOptions xoptions, GtkAttachOptions yoptions, guint xpadding, guint ypadding); The left, right, top, and bottom variables describe the location where the child widget should be placed within the table For example, the first GtkLabel in Listing 3-4 was attached with the following command: gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, GTK_EXPAND, GTK_SHRINK, 0, 0); 55 7931ch03.fm Page 56 Wednesday, March 7, 2007 8:54 PM 56 CHAPTER ■ CONTAINER WIDGETS The GtkLabel widget is attached directly to the first column and row of the table, because x coordinates are added, followed by y coordinates It is then attached to the second row on the bottom and the third column on the right The packing from the example in Listing 3-4 is shown in Figure 3-5 Figure 3-5 Table packing If you choose to have two columns, there will be three zero-indexed column attach points labeled The same logic applies to row attach points if there are two columns As previously stated, if a widget spans multiple cells, it must take up a rectangular area A widget could span two rows and one column with (0,1,0,2) or the whole table with (0,2,0,2) The best way to remember the order in which the attach points are specified is that both x coordinates come first, followed by the y coordinates After specifying attach points, you need to give attach options for the horizontal and vertical directions In our example, children are set to expand in the x direction and shrink in the y direction There are three values in the GtkAttachOptions enumeration: • GTK_EXPAND: The widget should take up extra space allocated to it by the table This space is allocated evenly between all children that specify this option • GTK_SHRINK: The widget should shrink so that it will only take up enough space to be rendered This is often used so that extra space is taken up by other widgets • GTK_FILL: The widget should fill all allocated space instead of filling the extra space with padding It is possible to give multiple attach option parameters by using a bitwise or operator For example, you can use GTK_EXPAND | GTK_FILL, so the child will take up extra space and fill it instead of adding padding 7931ch03.fm Page 57 Wednesday, March 7, 2007 8:54 PM CHAPTER ■ CONTAINER WIDGETS The last two parameters of gtk_table_attach() specify pixels of horizontal and vertical padding that should be added between the child and its neighbor cells void gtk_table_attach_defaults (GtkTable *table, GtkWidget *child, guint left, guint right, guint top, guint bottom); As with boxes, you not need to specify the full set of parameters when adding a child You can use gtk_table_attach_defaults() to add a child without specifying attach and padding options When using this function, GTK_EXPAND | GTK_FILL will be used for each attach option, and no padding will be added Table Spacing You can specify the spacing between columns or rows with gtk_table_attach(), but GTK+ provides four methods for changing these after adding a child If you want to set the spacing for every column in a table, you can use gtk_table_set_col_spacings() This function was used in Listing 3-4 to add five pixels of spacing GTK+ also provides gtk_table_set_row_spacings() to add padding between rows These functions will override any previous settings of the table void gtk_table_set_col_spacings (GtkTable *table, guint spacing); You may also set the spacing of one specific column or row with gtk_table_set_col_spacing() or gtk_table_set_row_spacing() These functions will add spacing between the child and its neighbors to the left and right of the widget or above and below it void gtk_table_set_col_spacing (GtkTable *table, guint column, guint spacing); Fixed Containers The GtkFixed widget is a type of layout container that allows you to place widgets by the pixel There are many problems that can arise when using this widget, but before we explore the drawbacks, let us look at a simple example Listing 3-5 creates a GtkFixed widget that contains two buttons, one found at each of the locations (0,0) and (20,30), with respect to the top-left corner of the widget 57 7931ch03.fm Page 58 Wednesday, March 7, 2007 8:54 PM 58 CHAPTER ■ CONTAINER WIDGETS Listing 3-5 Specifying Exact Locations (fixed.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *fixed, *button1, *button2; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Fixed"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); fixed = gtk_fixed_new (); button1 = gtk_button_new_with_label ("Pixel by pixel "); button2 = gtk_button_new_with_label ("you choose my fate."); g_signal_connect_swapped (G_OBJECT (button1), "clicked", G_CALLBACK (gtk_widget_destroy), (gpointer) window); g_signal_connect_swapped (G_OBJECT (button2), "clicked", G_CALLBACK (gtk_widget_destroy), (gpointer) window); /* Place two buttons on the GtkFixed container */ gtk_fixed_put (GTK_FIXED (fixed), button1, 0, 0); gtk_fixed_put (GTK_FIXED (fixed), button2, 20, 30); gtk_container_add (GTK_CONTAINER (window), fixed); gtk_widget_show_all (window); gtk_main (); return 0; } The GtkFixed widget, initialized with gtk_fixed_new(), allows you to place widgets with a specific size in a specific location Placing widgets is performed with gtk_fixed_put(), at specified horizontal and vertical positions void gtk_fixed_put (GtkFixed *fixed, GtkWidget *child, gint x, gint y); 7931ch03.fm Page 59 Wednesday, March 7, 2007 8:54 PM CHAPTER ■ CONTAINER WIDGETS The top-left corner of the fixed container is referred to by location (0,0) You should only be able to specify real locations for widgets or locations in positive space The fixed container will resize itself, so every widget is completely visible If you need to move a widget after it has been placed within a GtkFixed container, you can use gtk_fixed_move() You need to be careful not to overlap a widget that has already been placed The GtkFixed widget will not provide notification in the case of overlap Instead, it will try to render the window with unpredictable results void gtk_fixed_move (GtkFixed *fixed, GtkWidget *child, gint x_position, gint y_position); This brings us to the inherent problems with using the GtkFixed widget The first problem is that your users are free to use whatever theme they want This means that the size of text on the user’s machine may differ from the size of text on your machine unless you explicitly set the font The sizes of widgets vary among different user themes as well This can cause misalignment and overlap This is illustrated in Figure 3-6, which shows two screenshots of Listing 3-5, one with a small font size and one with a larger font size Figure 3-6 Problems caused by different font sizes in a GtkFixed container You can explicitly set the size and font of text to avoid overlap, but this is not advised in most cases Accessibility options are provided for users with low vision If you change their fonts, some users may not be able to read the text on the screen Another problem with using GtkFixed arises when your application is translated into other languages A user interface may look great in English, but the displayed strings in other languages may cause display problems, because the width will not be constant Furthermore, languages that are read right to left, such as Hebrew and Arabic, cannot be properly mirrored with the GtkFixed widget It is best to use a variable-sized container such as GtkBox or GtkTable in this case Finally, it can be quite a pain adding and removing widgets from your graphical interface when using a GtkFixed container Changing the user interface will require you to reposition all of your widgets If you have an application with a lot of widgets, this presents a long-term maintenance problem On the other hand, you have tables, boxes, and various other automatically formatting containers If you need to add or remove a widget from the user interface, it is as easy as adding or removing a cell This makes maintenance much more efficient, which is something you should consider in large applications 59 7931ch03.fm Page 60 Wednesday, March 7, 2007 8:54 PM 60 CHAPTER ■ CONTAINER WIDGETS Therefore, unless you know that none of the presented problems will plague your application, you should use variable-sized containers instead of GtkFixed This container was presented only so you know it is available if a suitable situation arises Even in suitable situations, flexible containers are almost always a better solution and are the proper way of doing things Expanders The GtkExpander container can handle only one child The child can be shown or hidden by clicking the triangle to the left of the expander’s label A before-and-after screenshot of this action can be viewed in Figure 3-7 Figure 3-7 A GtkExpander container Listing 3-6 was used to create Figure 3-7 The example introduces you to the most important GtkExpander methods Listing 3-6 Showing and Hiding Widgets (expanders.c) #include 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."); 7931ch03.fm Page 61 Wednesday, March 7, 2007 8:54 PM CHAPTER ■ CONTAINER WIDGETS 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 be created For example, whenever the user presses Alt+M on the keyboard in Listing 3-6, the widget will be activated Activating a GtkExpander widget will cause it to be expanded or retracted depending on its current state ■Tip Mnemonics are available in almost every widget that displays a label Where available, you 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 it with a second underscore If you not want to take advantage of the mnemonic feature, you can use gtk_expander_new() to initialize the GtkExpander with a standard string as the label, but providing mnemonics as an option to the user is always a good idea In normal expander 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 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 GtkExpander widget to be expanded The child widget of a GtkExpander container can be shown or hidden by calling 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); 61 7931ch03.fm Page 62 Wednesday, March 7, 2007 8:54 PM 62 CHAPTER ■ CONTAINER WIDGETS Handle Boxes The 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 ghost is 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 An example of a GtkHandleBox widget is shown in Figure 3-8 It shows the handle box attached to the window and then removed The handle box can be reattached by aligning it with the original location 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 example shows all of the properties available to you through the GtkHandleBox class Listing 3-7 Detachable Widgets (handleboxes.c) #include 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); 7931ch04.fm Page 82 Monday, February 5, 2007 8:25 PM 82 CHAPTER ■ BASIC WIDGETS Excluding the initialization methods, all functionality for check boxes is implemented in the GtkToggleButton class and its ancestors GtkCheckButton is merely a convenience widget, which provides the graphical differences from standard GtkButton widgets Radio Buttons The second type of widget derived from GtkToggleButton is the radio button widget In fact, GtkRadioButton is actually derived from GtkCheckButton Radio buttons are toggles that are generally grouped together In a group, when one radio button is selected, all others will be deselected The group forbids selecting multiple radio buttons at once This allows you to provide multiple options to the user where only one should be selected ■Note There is no way provided by GTK+ to deselect a radio button, so a group of one radio button is not desirable The user will not be able to deselect the option! In the case that you only need one button, you should use a GtkCheckButton or GtkToggleButton widget Radio buttons are drawn as a discrete circular toggle to the side of the label widget, so they can be differentiated from other types of toggle buttons It is possible to draw radio buttons with the same toggle as GtkCheckButton, but this should not be done, because it can confuse and frustrate the user A group of four radio buttons in a vertical box is shown in Figure 4-4 Figure 4-4 Radio buttons For radio buttons to work correctly, they must all be referenced to another radio button in the group Otherwise, all of the buttons would act as independent toggle buttons An example of how to use multiple radio buttons is shown in Listing 4-4 7931ch04.fm Page 83 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS Listing 4-4 Selfish Toggle Buttons (radiobuttons.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *vbox, *radio1, *radio2, *radio3; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Radio Buttons"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); /* Create three radio buttons where the second two join radio1's group */ radio1 = gtk_radio_button_new_with_label (NULL, "I want to be clicked!"); radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1), "Click me instead!"); radio3 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1), "No! Click me!"); /* Note: The radio button you create the new widget from does not matter as * long as it is already a member of the group! */ radio4 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio3), "No! Click me instead!"); vbox = gtk_vbox_new (FALSE, gtk_box_pack_start_defaults gtk_box_pack_start_defaults gtk_box_pack_start_defaults gtk_box_pack_start_defaults 5); (GTK_BOX (GTK_BOX (GTK_BOX (GTK_BOX (vbox), (vbox), (vbox), (vbox), radio1); radio2); radio3); radio4); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } 83 7931ch04.fm Page 84 Monday, February 5, 2007 8:25 PM 84 CHAPTER ■ BASIC WIDGETS The first radio button in a group can be created with any of the following three functions However, if you want to use a GtkLabel widget as the child, it is also possible to use a mnemonic widget, so the toggle can be activated from the keyboard GtkWidget* gtk_radio_button_new GtkWidget* gtk_radio_button_new_with_label (GSList *group); (GSList *group, const gchar *label); GtkWidget* gtk_radio_button_new_with_mnemonic (GSList *group, const gchar *label); You will notice that NULL is specified for the radio group in each call This is because the simplest way to create a group of radio buttons is to associate them to another widget in the group By using this method, you avoid having to use the GLib with singly linked lists, since the list will be created and managed for you automatically (GSList data structures will be covered later in Chapters and 6.) You can create any type of toggle button, including radio buttons, without a label, in which case you would add your own child widget with gtk_container_add() You can also create radio buttons with a programmatically defined label or a mnemonic label The easiest way to create the rest of the radio buttons is with one of the following three _from_widget() functions Similar to creating the first radio button, these can be created with a label, a mnemonic label, or without an initial child widget GtkWidget* gtk_radio_button_new_from_widget GtkWidget* gtk_radio_button_new_with_label_from_widget (GtkRadioButton *group); (GtkRadioButton *group, const gchar *label); GtkWidget* gtk_radio_button_new_with_mnemonic_from_widget (GtkRadioButton *group, const gchar *label); Referring the initialization function to a radio button that already exists creates each of these GTK+ will add the new radio button to the group from the specified widget Because of this, you need only refer to any widget that already exists within the desired radio group Lastly, every radio button in the group must be connected to the toggled signal When a radio button is selected, only two radio buttons will emit the toggled signal, because one will be selected, and another will be deselected You will not be able to catch all radio button signals if you not connect every radio button to toggled Text Entries The GtkEntry widget is a single line, free-form text entry widget It is implemented in a general manner, so that it can be molded to fit many types of solutions It can be used for text entry, password entry, and even number selections GtkEntry also implements the GtkEditable interface, which provides a large number of functions that are created to handle selections of text An example GtkEntry widget is shown in Figure 4-5 This text entry is used for password entry 7931ch04.fm Page 85 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS Figure 4-5 A password text entry ■Note GtkEditable is a special type of object called an interface An interface is a set of APIs that are implemented by multiple widgets and used for consistency You will learn how to implement and utilize interfaces in your own widgets in Chapter 11 The GtkEntry widget considers all text to be standard strings The only way it differentiates between normal text and passwords is that a special character called an invisibility character is shown instead of password content Listing 4-5 shows you how to use a GtkEntry widget for password entry If you want to use a GtkEntry widget for normal text entry, you need only to turn visibility on Listing 4-5 Retrieving User Information (entries.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *vbox, *hbox, *question, *label, *pass; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Password?"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); str = g_strconcat ("What is the password for ", g_get_user_name(), "?", NULL); question = gtk_label_new (str); label = gtk_label_new ("Password:"); /* Create a new GtkEntry widget and hide its content from view */ pass = gtk_entry_new (); gtk_entry_set_visibility (GTK_ENTRY (pass), FALSE); gtk_entry_set_invisible_char (GTK_ENTRY (pass), '*'); 85 7931ch04.fm Page 86 Monday, February 5, 2007 8:25 PM 86 CHAPTER ■ BASIC WIDGETS hbox = gtk_hbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (hbox), label); gtk_box_pack_start_defaults (GTK_BOX (hbox), pass); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), question); gtk_box_pack_start_defaults (GTK_BOX (vbox), hbox); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } Entry Properties The GtkEntry widget is a highly flexible widget, because it was designed to be employed in the maximum number of instances This can be seen from the wide array of properties provided by the class A sampling of the most important of those is included in this section For a full list of properties, you should reference Appendix A Text does not always have to be editable in a GtkEntry widget If you set the entry as noneditable with gtk_editable_set_editable(), the user will not be able to edit the text However, the user will still be able to use the selection and copy functionality of the GtkEntry widget, because this property is not the same thing as setting the widget as insensitive void gtk_editable_set_editable (GtkEditable *editable, gboolean is_editable); Oftentimes, you will want to restrict the length of the free-form text entered into an entry widget because of string limitations of the value In the following function prototype, gtk_entry_set_max_length() limits the text of the entry to max_length characters This can be useful when you want to limit the length of user names, passwords, or other length-sensitive information void gtk_entry_set_max_length (GtkEntry *entry, gint max_length); Invisibility characters facilitate password entries in GTK+ The invisibility character is the character that will replace the actual password content in the entry, which can be set with gtk_entry_set_invisible_char() The default character for the entry is an asterisk void gtk_entry_set_invisible_char (GtkEntry gunichar void gtk_entry_set_visibility (GtkEntry gboolean *entry, inv_char); *entry, visible); After specifying the invisibility character, you can hide all entered text by setting visibility to FALSE with gtk_entry_set_visiblity() You will still be able to retrieve the actual content of the entry programmatically even though it is hidden from view 7931ch04.fm Page 87 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS Inserting Text into a GtkEntry Widget There are multiple ways to insert text to a GtkEntry widget The simplest way is to use gtk_entry_set_text(), which will overwrite the whole content of the text entry with the given string However, this is only useful if you no longer care about the current text displayed by the widget void gtk_entry_set_text (GtkEntry *entry, const gchar *text); The current text displayed by GtkEntry can be retrieved with gtk_entry_get_text() This string is used internally by the widget and must never be freed or modified in any way It is also possible to use gtk_editable_insert_text() to insert text into a GtkEntry widget This function accepts the text to insert, the length of the text in bytes, and the position where the text should be inserted void gtk_editable_insert_text (GtkEditable *editable, const gchar *text, gint length_of_text, gint *position); There are also functions provided for prepending and appending text, but these are not needed, since you can perform these functions by providing positions of and -1, respectively, to gtk_editable_insert_text() Manipulating GtkEntry Text Deleting specific content from a text entry is easy with gtk_editable_delete_text() It will remove all of the text between the two positions specified but not the character at the end position void gtk_editable_delete_text (GtkEditable *editable, gint start_pos, gint end_pos); When using gtk_editable_delete_text(), the order of the positions that you specify does not matter Also, if you specify -1 as the end position, the characters from the start position to the end of the text will be deleted If you need a specific region of text to be selected automatically, this can be done with gtk_editable_select_region() As with deleting text, an end position of -1 will select all of the text from the start position to the end of the content Manual and automatic selections are what facilitate the following few functions void gtk_editable_select_region (GtkEditable *editable, gint start_pos, gint end_pos); Once you are able to select text, it would be useful to be able to delete the selection This is very easy to with gtk_editable_delete_selection() This function will delete all of the selected text, leaving any nonselected text 87 7931ch04.fm Page 88 Monday, February 5, 2007 8:25 PM 88 CHAPTER ■ BASIC WIDGETS void gtk_editable_delete_selection (GtkEditable *editable); In addition to retrieving the whole textual content of the widget, it is possible to retrieve only a section of the text with gtk_editable_get_chars() This will return a copy of the specified string, which must be freed with g_free() when you are finished with it gchar* gtk_editable_get_chars (GtkEditable *editable, gint start_pos, gint end_pos); The following three functions perform various clipboard functions There are keyboard accelerators for cutting (Ctrl+X), copying (Ctrl+C), and pasting (Ctrl+V) built into entries by default Therefore, you will not usually need to implement clipboard functionality when using a GtkEntry widget void gtk_editable_cut_clipboard (GtkEditable *editable); void gtk_editable_copy_clipboard (GtkEditable *editable); void gtk_editable_paste_clipboard (GtkEditable *editable); Spin Buttons The GtkSpinButton widget is a number selection widget that is capable of handling integers and floating-point numbers It is derived from GtkEntry, so GtkSpinButton inherits all of its functions and signals Adjustments Before covering the GtkSpinButton widget, you must understand the GtkAdjustment class GtkAdjustment is one of the few classes in GTK+ that is not considered a widget, because it is derived directly from GtkObject It is used for several widgets including spin buttons, view ports, and the multiple widgets derived from GtkRange New adjustments are created with gtk_adjustment_new(), although they are usually cast with GTK_ADJUSTMENT() upon initialization, because storage as a GtkObject is not practical Once added to a widget, memory management of the adjustment is handled by the widget, so you not have to worry about this aspect of the object GtkObject* gtk_adjustment_new (gdouble gdouble gdouble gdouble gdouble gdouble initial_value, lower_range, upper_range, step_increment, page_increment, page_size); 7931ch04.fm Page 89 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS New adjustments are initialized with six parameters A list of these parameters follows • initial_value: The value stored by the adjustment when it is initialized This corresponds to the value property of the GtkAdjustment class • lower_range: The minimum value the adjustment will be allowed to hold This corresponds to the lower property of the GtkAdjustment class • upper_range: The maximum value the adjustment will be allowed to hold This corresponds to the upper property of the GtkAdjustment class • step_increment: The increment to make the smallest change possible If you want to count all integers between and 10, the increment would be set to • page_increment: The increment to make when Page Up or Page Down is pressed This is almost always larger than the step_increment • page_size: The size of a page This value does not have much use in a GtkSpinButton, so it should be set to the same value as page_increment or to There are two useful signals provided by the GtkAdjustment class: changed and valuechanged The changed signal is emitted when one or more properties of the adjustment have been altered, excluding the value property The value-changed signal is emitted when the current value of the adjustment has been altered A Spin Button Example The spin button widget allows the user to select an integer or floating-point number by incrementing or decrementing with the up or down arrows The user can still type in a value with the keyboard, and it will be displayed as the nearest acceptable value if it is out of range Figure 4-6 shows two spin buttons in action that display an integer and a floating-point number Figure 4-6 Spin buttons As previously stated, spin buttons can be used to show integer or floating-point numbers In actuality, numbers are stored as gdouble values The spin button handles rounding the number to the correct number of decimal places Listing 4-6 is a simple example that creates both integer and floating-point number spin buttons 89 7931ch04.fm Page 90 Monday, February 5, 2007 8:25 PM 90 CHAPTER ■ BASIC WIDGETS Listing 4-6 Integer and Floating-point Number Selection (spinbuttons.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *spin_int, *spin_float, *vbox; GtkAdjustment *integer, *float_pt; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Spin Buttons"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 150, 100); /* Create two new adjustments The first spans between and 10, starting at and * moves in increments of The second spans between and 1, starting at 0.5 and * moves in increments of 0.1 */ integer = GTK_ADJUSTMENT (gtk_adjustment_new (5.0, 0.0, 10.0, 1.0, 2.0, 2.0)); float_pt = GTK_ADJUSTMENT (gtk_adjustment_new (0.5, 0.0, 1.0, 0.1, 0.5, 0.5)); /* Create two new spin buttons The first will display no decimal places and the * second will display one decimal place */ spin_int = gtk_spin_button_new (integer, 1.0, 0); spin_float = gtk_spin_button_new (float_pt, 0.1, 1); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), spin_int); gtk_box_pack_start_defaults (GTK_BOX (vbox), spin_float); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } Before creating the spin buttons, you should create the adjustments You can also initialize the spin button with a NULL adjustment, but it will be set as insensitive After your adjustments are initialized, you can create new spin buttons with gtk_spin_button_new() The other two parameters in the initialization function specify the climb rate of the spin button and the number of decimal places to display The climb 7931ch04.fm Page 91 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS rate is how much the value should be incremented or decremented when an arrow button is pressed GtkWidget *gtk_spin_button_new (GtkAdjustment *adjustment, gdouble climb_rate, guint digits); Alternatively, you can create a new spin button with gtk_spin_button_new_with_range(), which will automatically create a new adjustment based on the minimum, maximum, and step values you specify The initial value is set to the minimum value plus a page increment of ten times the step_increment by default The precision of the widget is automatically set to the value of step_increment GtkWidget* gtk_spin_button_new_with_range (gdouble minimum_value, gdouble maximum_value, gdouble step_increment); You can call gtk_spin_button_set_digits() to set a new precision of the spin button and gtk_spin_button_set_value() to set a new value The value will automatically be altered if it is out of bounds of the spin button void gtk_spin_button_set_value (GtkSpinButton *spin_button, gdouble value); Horizontal and Vertical Scales Another type of widget called a scale allows you to provide a horizontal or vertical slider that can choose an integer or a floating-point number GtkHScale is a horizontal scale widget, and GtkVScale is a vertical scale widget Both of these classes are derived from GtkScale, which provides properties, signals, and functions The functionality of the GtkScale widget is not much different from GtkSpinButton It is often used when you want to restrict the user from entering values, since the value is chosen by moving the slider Figure 4-7 shows a screenshot of two horizontal scale widgets Figure 4-7 Horizontal scale widgets Scales provide essentially the same functionality as spin buttons, except using a slider chooses the number To show the similarities between the widgets, Listing 4-7 implements the same functionality as Listing 4-6: two sliders allow the user to select an integer and a floating-point number 91 7931ch04.fm Page 92 Monday, February 5, 2007 8:25 PM 92 CHAPTER ■ BASIC WIDGETS Listing 4-7 Integer and Floating-point Number Selection with Scales (scales.c) #include int main (int argc, char *argv[]) { GtkWidget *window, *scale_int, *scale_float, *vbox; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); gtk_window_set_title (GTK_WINDOW (window), "Scales"); gtk_container_set_border_width (GTK_CONTAINER (window), 10); gtk_widget_set_size_request (window, 250, -1); /* Create a scale that scrolls integers and one that scrolls floating point */ scale_int = gtk_hscale_new_with_range (0.0, 10.0, 1.0); scale_float = gtk_hscale_new_with_range (0.0, 1.0, 0.1); /* Set the number of decimal places to display for each widget */ gtk_scale_set_digits (GTK_SCALE (scale_int), 0); gtk_scale_set_digits (GTK_SCALE (scale_float), 1); /* Set the position of the value with respect to the widget */ gtk_scale_set_value_pos (GTK_SCALE (scale_int), GTK_POS_RIGHT); gtk_scale_set_value_pos (GTK_SCALE (scale_float), GTK_POS_LEFT); vbox = gtk_vbox_new (FALSE, 5); gtk_box_pack_start_defaults (GTK_BOX (vbox), scale_int); gtk_box_pack_start_defaults (GTK_BOX (vbox), scale_float); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show_all (window); gtk_main (); return 0; } There are two ways to create new scale widgets The first is with gtk_hscale_new() or gtk_vscale_new(), which accepts a GtkAdjustment that defines how the scale will work GtkWidget *gtk_hscale_new (GtkAdjustment *adjustment); Alternatively, you can create scales with gtk_hscale_new_with_range() or gtk_vscale_new_with_range() This function accepts the minimum value, the maximum value, and the step increment of the scale 7931ch04.fm Page 93 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS GtkWidget *gtk_hscale_new_with_range (gdouble minimum, gdouble maximum, gdouble step); Since the value of the scale is always stored as a gdouble, you will need to define the number of decimal places to show with gtk_scale_set_digits() if the default value is not what you want The default number of decimal places is calculated based on the number of decimal places provided for the step increment For example, if you provide a step increment of 0.01, two decimal places will be displayed by default void gtk_scale_set_digits (GtkScale *scale, gint digits); Depending on what type of scale widget you are using, you may want to change where the value is displayed with gtk_scale_set_value_pos() Positions are defined by the GtkPositionType enumeration, and they are GTK_POS_LEFT, GTK_POS_RIGHT, GTK_POS_TOP, and GTK_POS_BOTTOM You can also use gtk_scale_set_draw_value() to hide the value from the user’s view altogether void gtk_scale_set_value_pos (GtkScale *scale, GtkPositionType pos); GtkScale is derived from a widget called GtkRange This widget is an abstract type that provides the ability to handle an adjustment Because of this, you should use gtk_range_get_value() to retrieve the current value of the scale GtkRange also provides the value-changed signal, which is emitted when the user changes the position of the scale Widget Styles In the next few sections, you will be editing widget style properties, so it is time to learn about the GtkStyle structure and resource files Resource files are external collections of style settings that can be loaded and applied to your application during runtime to allow for further customization The GtkStyle Structure Every GtkWidget has five public members, which are shown in the following code snippet These are style information, size requisition, size allocation, a GdkWindow that is used to draw the widget on the screen, and a pointer to the parent widget typedef struct { GtkStyle *style; GtkRequisition requisition; GtkAllocation allocation; GdkWindow *window; GtkWidget *parent; } GtkWidget; 93 7931ch04.fm Page 94 Monday, February 5, 2007 8:25 PM 94 CHAPTER ■ BASIC WIDGETS The GtkStyle structure stores drawing information about the widget The content of the structure follows: typedef struct { GdkColor fg[5] GdkColor bg[5] GdkColor light[5] GdkColor dark[5] GdkColor mid[5] GdkColor text[5] GdkColor base[5] GdkColor text_aa[5]; GdkColor black, white; /* /* /* /* /* /* /* /* /* The foreground color for most widgets */ The background color for most widgets */ Lighter colors used for creating widget shadows */ Darker colors used for creating widget shadows */ The color midway between light and dark */ The text color for most text widgets */ The background color used for text-editing widgets */ Used for anti-aliased text colors */ Colors that represent "Black" and "White" */ PangoFontDescription *font_desc; gint xthickness, ythickness; GdkPixmap *bg_pixmap[5]; /* The default text font */ /* Thickness of lines */ /* Background image to use for a widget */ /* Graphics contexts that hold drawing properties for each color and state */ GdkGC *fg_gc [5], *bg_gc [5], *light_gc[5], *dark_gc[5], *mid_gc[5], *text_gc[5], *base_gc[5], *text_aa_gc[5]; GdkGC *black_gc, *white_gc; } GtkStyle; There are many objects in the GtkStyle structure Each of these will have a default value set by the user’s style, so overriding them may not always be a good idea However, if it is necessary, editing a widget’s GtkStyle is a simple way to change how it is displayed You will notice that many of the style properties are arrays of file elements This is because each of these elements can have different values for one of the following five possible widget states: • GTK_STATE_NORMAL: The widget during normal operation • GTK_STATE_ACTIVE: An active widget, such as when a toggle is depressed • GTK_STATE_PRELIGHT: A widget when the mouse pointer is over the widget; it will respond to button clicks • GTK_STATE_SELECTED: A widget when the widget or its text has been selected • GTK_STATE_INSENSITIVE: A widget is deactivated and will not respond to the user Resource Files GTK+ provides a way for applications to use user-defined styles called resource files (RC files) RC files allow the user to define styles for widget types or individual widgets, which can be changed to fit the user’s preferences These are usually stored in the user’s home directory along with other application data, so that the user has permissions to alter the settings 7931ch04.fm Page 95 Monday, February 5, 2007 8:25 PM CHAPTER ■ BASIC WIDGETS To load a resource file, you should call gtk_rc_parse() when loading your application This will automatically apply the styles on all appropriate widgets void gtk_rc_parse (const gchar *filename); Also, if you want to directly reference a widget from an RC file, you need to use gtk_widget_set_name() to set a unique name for the widget This name will be used in the RC file to set the widget’s style and/or the styles of its children In Listing 4-8, a simple example RC file is shown In this example, multiple widget styles are created, each style containing a number of properties Listing 4-8 Defining Widget Styles (.gtkrc) style "widgets" { xthickness = ythickness = fg[ACTIVE] = "#FFFFFF" fg[SELECTED] = "#003366" fg[NORMAL] = "#CCCCCC" fg[PRELIGHT] = "#FFFFFF" fg[INSENSITIVE] = "#999999" bg[ACTIVE] = "#003366" bg[SELECTED] = "#FFFFFF" bg[NORMAL] = "#666666" bg[PRELIGHT] = "#003366" bg[INSENSITIVE] = "#666666" } style "labels" = "widgets" { font_name = "Sans Bold 14" } style "buttons" = "widgets" { GtkButton::inner-border = { 10, 10, 10, 10 } } style "checks" = "buttons" { GtkCheckButton::indicator-size = 25 } class class class class "GtkWindow" style "widgets" "GtkLabel" style "labels" "GtkCheckButton" style "checks" "Gtk*Button" style "buttons" 95 7931ch04.fm Page 96 Monday, February 5, 2007 8:25 PM 96 CHAPTER ■ BASIC WIDGETS Figure 4-8 shows an application that is taking advantage of the RC file shown in Listing 4-8 The colors and font are different from the examples found in the past few chapters Figure 4-8 An example application using gtkrc If you would like to explore the standard styles available to all widgets in RC files, you should read Appendix C This section will teach you how to apply those styles in your own applications Styles can be applied by the widget type with the class directive as shown in the preceding example In this example, the buttons style is applied to all Gtk*Button* widgets, where the asterisk is used as a wildcard This is applied to every widget in the application that has a matching class name class "Gtk*Button" style "buttons" The second method for applying a widget style is based on a hierarchy pattern with the widget directive This example applies the stylename style to all direct and indirect children of widgetname that are of the type GtkButton widget "widgetname.*.GtkButton" style "stylename" In addition to the asterisk wildcard that matches zero or more of any character, you can use a question mark wildcard to match one or more of any character Also, widget hierarchy is shown by using a period, where the widget to the right of the period is the child of the widget to the left The problem with the widget directive is that if a name is specified for the widget, it must be used instead of the class name If you only want to use widget classes, you can use the widget_class directive This allows you to ignore all widget names and apply a style to all widgets that follow the specified pattern ... container */ gtk_ table_attach (GTK_ TABLE (table), label, 0, 2, 0, 1, GTK_ EXPAND, GTK_ SHRINK, 0, 0); gtk_ table_attach (GTK_ TABLE (table), label2, 0, 1, 1, 2, GTK_ EXPAND, GTK_ SHRINK, 0, 0); gtk_ table_attach... container */ gtk_ fixed_put (GTK_ FIXED (fixed), button1, 0, 0); gtk_ fixed_put (GTK_ FIXED (fixed), button2, 20 , 30); gtk_ container_add (GTK_ CONTAINER (window), fixed); gtk_ widget_show_all (window); gtk_ main... int main (int argc, char *argv[]) { GtkWidget *window, *fixed, *button1, *button2; gtk_ init (&argc, &argv); window = gtk_ window_new (GTK_ WINDOW_TOPLEVEL); gtk_ window_set_title (GTK_ WINDOW

Ngày đăng: 05/08/2014, 10:20

Từ khóa liên quan

Mục lục

  • Chapter 4

Tài liệu cùng người dùng

  • Đang cập nhật ...

Tài liệu liên quan