When your application needs to tell the user about something important or obtain some information before proceeding with an operation, you should create a dialog (sometimes called a dialog box ). GTK+ has standard prepackaged dialogs with a uniform look; all you need to do is create and manipulate objects of the GtkDialog class ( GTK_TYPE_DIALOG ).
An example program with a dialog box follows , starting with the standard event handlers and then a handler for the dialog box:
/* -*-coding: utf-8;-*- */ /* dialog.c -- demonstrate a dialog box */ #include <gtk/gtk.h> << standard window handlers >> /* handler for "response" signal from dialog */ void dialog_action(GtkDialog *dialog, gint response, gpointer data) { g_assert(response == GTK_RESPONSE_ACCEPT response == GTK_RESPONSE_REJECT); switch (response) { case GTK_RESPONSE_ACCEPT: g_print("Planet destroyed.\n"); break; case GTK_RESPONSE_REJECT: g_print("Planet destruction aborted.\n"); break; default: /* do nothing */ break; } }
As you might suspect from the comment earlier, GTK+ emits a response signal when the user does something with the dialog box. The handler's response parameter contains the details (you'll find more information later in this section).
There is nothing unusual about the start of the main program:
int main(int argc, char **argv) { GtkWindow *window; GtkButton *button; GtkDialog *dialog; GtkHBox *dialog_hbox; GtkImage *dialog_icon; GtkLabel *dialog_text; /* initialize GTK, create window */ gtk_init(&argc, &argv); window = g_object_new(GTK_TYPE_WINDOW, "default_height", 200, "default_width", 200, "border-width", 12, "title", "Dialog Demo", NULL); << attach standard window handlers >>
The following code creates a standard dialog box with two buttons . Each button gets a label and a response code (this should be one of the standard responses listed on page 192). You can set a default response.
/* create dialog box */ dialog = GTK_DIALOG(gtk_dialog_new_with_buttons( "Destroy Planet?", /* title */ window, /* parent */ GTK_DIALOG_DESTROY_WITH_PARENT, /* options */ /* list of button labels and responses */ "_Destroy", GTK_RESPONSE_ACCEPT, "_Abort Destruction", GTK_RESPONSE_REJECT, NULL)); gtk_dialog_set_default_response(dialog, GTK_RESPONSE_REJECT);
The following handler attachment connects all of the buttons and responses in the preceding code to the signal handler defined earlier. You have probably noticed by now that creating the dialog boxes in this manner involves significantly less work (for starters, you do not have to create any individual button widgets or worry about their handlers).
/* attach handler for dialog response */ g_signal_connect(dialog, "response", G_CALLBACK(dialog_action), NULL);
Getting rid of the dialog box when the user clicks one of its buttons is just a matter of attaching a GTK+ widget destroy function to the response handler sequence:
/* remove dialog box when it returns a response */ g_signal_connect_swapped(dialog, "response", G_CALLBACK(gtk_widget_destroy), window);
The only real work left to do is to create the dialog's actual contents (other than the buttons). The following creates an HBox with a custom message along with a stock image:
/* fill dialog window: create HBox packed with icon and Text */ dialog_hbox = g_object_new(GTK_TYPE_HBOX, "border-width", 8, NULL); dialog_icon = g_object_new(GTK_TYPE_IMAGE, "stock", GTK_STOCK_DIALOG_WARNING, "icon-size", GTK_ICON_SIZE_DIALOG, "xalign", 0.5, "yalign", 1.0, NULL); gtk_box_pack_start(GTK_BOX(dialog_hbox), GTK_WIDGET(dialog_icon), FALSE, FALSE, 0); dialog_text = g_object_new(GTK_TYPE_LABEL, "wrap", TRUE, "use-markup", TRUE, "label", "\ <big><b>Do you really want to destroy the planet?</b></big>\ \n\ Please note that the annihilation of a planet is rarely \ regarded as a successful show of environmentally \ friendly behavior."); gtk_box_pack_start(GTK_BOX(dialog_hbox), GTK_WIDGET(dialog_text), TRUE, TRUE, 0);
You want to be able to put your new message in the dialog. Do this by packing it into the dialog's vbox field. This function call packs the message directly above the buttons:
/* pack HBox into dialog */ gtk_box_pack_start(GTK_BOX(dialog->vbox), GTK_WIDGET(dialog_hbox), FALSE, FALSE, 0);
Normally, you don't bring up a dialog box as the main window. Therefore, the following creates a button for the main window. When you click the button, the dialog appears.
/* create button for main window */ button = g_object_new(GTK_TYPE_BUTTON, "label", "_Show dialog", "use-underline", TRUE, NULL); /* show the dialog when user clicks button */ g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_show_all), dialog); /* pack button, show everything, start main loop */ gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button)); gtk_widget_show_all(GTK_WIDGET(window)); gtk_main(); return 0; }
Figure 3.16 shows the dialog part of the application.
As you saw from this example, the generator function
gtk_dialog_new_with_buttons( title , parent , options , ...)
offers a good way to create a dialog box with buttons (there are more awkward ways, trust me). The options value is a bitwise OR of these constants:
GTK_DIALOG_MODAL : For modal dialogs (these lock the input focus). Section 3.2 describes why you should be careful with these.
GTK_DIALOG_DESTROY_WITH_PARENT : Removes the dialog window when the parent is destroyed.
Warning | If you set this option, keep in mind that some outside action can remove the dialog. In any case, make sure that you write a clean destroy signal handler that adequately resolves the dialog's question. |
GTK_DIALOG_NO_SEPARATOR : Don't place a horizontal separator between the dialog's lower buttons and the rest of the window.
The button list ( ... in the parameters) consists of label string/response code pairs. A NULL value terminates the list. You can use any positive integer for the response code, but you should always see whether one of the predefined GTK_RESPONSE_ codes (discussed in a moment) is appropriate first.
When the user clicks a button, GTK+ emits the reponse signal with the dialog box. The handler prototype should look like this:
void handler(GtkDialog * dialog , gint response , gpointer data )
The response parameter is the response code from the button clicked. Here are some predefined codes:
GTK_RESPONSE_NONE : The response when the application removes the dialog.
GTK_RESPONSE_DELETE_EVENT : The user or window manager wants to delete the window.
GTK_RESPONSE_ACCEPT
GTK_RESPONSE_REJECT
GTK_RESPONSE_OK
GTK_RESPONSE_CANCEL
GTK_RESPONSE_CLOSE
GTK_RESPONSE_YES
GTK_RESPONSE_NO
GTK_RESPONSE_APPLY
GTK_RESPONSE_HELP
As you can see from the example, creating dialogs in this manner is relatively easy because you need only create one handler. In that handler, you can use a switch statement to decipher the response code and carry out the appropriate action. You also saw that you can use the following
gtk_dialog_set_default_response( dialog , code )
to set a default button in the dialog (the one that gets the input focus).
Note | To make your dialogs as consistent and clear as possible, follow these guidelines:
|
Finally, you should remember that you can pack any widgets into the vbox of a dialog box. Therefore, you can ask for some additional data in a dialog. This is usually preferable to doing everything by hand, because GtkDialog does a lot of behind-the-scenes work with the window manager and other pieces of the system to make dialogs behave like dialogs. Otherwise, you would need to do this by hand ” an almost certain waste of time and energy.