This chapter introduces you to a special type of window called a dialog. Dialogs are windows that supplement the top-level window. The dialog is provided by Gtk.Dialog , a child class of Gtk.Window, extended with additional functionality. This means that it is possible to implement your entire interface in one or more dialogs, while leaving the main window hidden.
You can do anything with a dialog, such as display a message or prompt the user to select an option. Their purpose is to enhance user experience by providing some type of transient functionality.
In the first part of the chapter, you learn how to use Gtk.Dialog to create your own custom dialogs. The next section introduces the large number of built-in dialogs provided by GTK+. Lastly, you learn about a widget called Gtk.Assistant that allows you to create dialogs with multiple pages; assistants are meant to help the user through a multistage process.
How to create your own custom dialogs using the Gtk.Dialog widget
How to give general information, error messages, and warnings to the user with the Gtk.MessageDialog widget
How to provide information about your application with Gtk.AboutDialog
What types of file chooser dialogs are available
The ways to collect information with font and color selection dialogs
How to create dialogs with multiple pages using the Gtk.Assistant widget
Creating Your Own Dialogs
A dialog is a special type of Gtk.Window that supplements the top-level window. It can give the user a message, retrieve information from the user, or provide some other transient type of action.
Dialog widgets are split in half by an invisible horizontal separator. The top part is where you place the main part of the dialog’s user interface. The bottom half is called the action area, and it holds a collection of buttons. When clicked, each button emits a unique response identifier that tells the programmer which button was clicked.
Gtk.Dialog provides access a vertical box that has the action area defined at bottom of the box. The content area has yet to be defined. To define it you begin packing widgets at start of the vertical box. Therefore you must always use the pack_start() to add widgets to a Gtk.Dialog class. Buttons can easily be added to the action area with the add_button(button_text, response_id) method call.
Note
It is possible to manually implement the functionality of Gtk.Dialog by creating a Gtk.Window with all of the same widgets and establishing window relationships with set_transient_for() in addition to other functions provided by Gtk.Window. Gtk.Dialog is simply a convenience widget that provides standard methods.
By packing widgets at the start of the box, the action area and the separator always remains at the bottom of the dialog.
Creating a Message Dialog
Your First Custom Dialog
Creating the Dialog
The dialog is set as the transient window of the parent window, which allows the window manager to center the dialog over the main window and keep it on top if necessary. This can be achieved for arbitrary windows by calling window.set_transient_for(). You can also provide None if you do not want the dialog to have or recognize a parent window.
Gtk.DialogFlags.MODAL: Force the dialog to remain in focus on top of the parent window until closed. The user is prevented from interacting with the parent.
Gtk.DialogFlags.DESTROY_WITH_PARENT: Destroy the dialog when the parent is destroyed, but do not force the dialog to be in focus. This creates a nonmodal dialog unless you call dialog.run().
Gtk.DialogFlags.USE_HEADER_BAR: Create a dialog with actions in the header bar instead of the action area.
In Listing 6-1, specifying Gtk.DialogFlags.MODAL created a modal dialog. It is not necessary to specify a title or parent window; the values can be set to None. However, you should always set the title, so it can be drawn in the window manager; otherwise, the user has difficulty choosing the desired window.
In Listing 6-1, an OK button with a response of Gtk.ResponseType.OK was added to the dialog.
In GTK+ 2.x, all dialogs placed a horizontal separator between the main content and the action area of the dialog by default. That separator has been deprecated in GTK+ 3.x.
At this point, you need to show the dialog and its child widgets, because dialog.run()only calls dialog.show() on the dialog itself. To do this, call dialog.show_all() on the dialog. If you do not show the widgets, only the separator and action area is visible when dialog.run() is called.
Response Identifiers
Internally, dialog.run() creates a new main loop for the dialog, which prevents you from interacting with its parent window until a response identifier is emitted or the user closes the dialog. Regardless of what dialog flags you set, the dialog is always modal when you call this method, because it calls dialog.set_modal().
Gtk.ResponseType Enumeration Values
Identifiers | Value | Description |
---|---|---|
Gtk.ResponseType.NONE | –1 | Returned if an action widget has no response ID, or if the dialog is programmatically hidden or destroyed. |
Gtk.ResponseType.APPLY | –10 | Returned by Apply buttons in GTK+ dialogs. |
Gtk.ResponseType.HELP | –11 | Returned by Help buttons in GTK+ dialogs. |
Gtk.ResponseType.REJECT | –2 | Generic response ID, not used by GTK+ dialogs. |
Gtk.ResponseType.ACCEPT | –3 | Generic response ID, not used by GTK+ dialogs. |
Gtk.ResponseType.DELETE_EVENT | –4 | Returned if the dialog is deleted. |
Gtk.ResponseType.OK | –5 | Returned by OK buttons in GTK + dialogs. |
Gtk.ResponseType.CANCEL | –6 | Returned by Cancel buttons in GTK+ dialogs. |
Gtk.ResponseType.CLOSE | –7 | Returned by Close buttons in GTK+ dialogs. |
Gtk.ResponseType.YES | –8 | Returned by Yes buttons in GTK + dialogs. |
Gtk.ResponseType.No | –9 | Returned by No buttons in GTK+ dialogs. |
Of course, when you create your own dialogs and when using many of the built-in dialogs covered in the next few pages, you are free to choose which response identifier to use. However, you should try to resist the urge to apply a Gtk.ResponseType.CANCEL identifier to an OK button, or some other type of absurdity along those lines.
Note
You are free to create your own response identifiers, but you should use positive numbers, since all of the built-in identifiers are negative. This allows you to avoid conflicts when more identifiers are added in future versions of GTK+.
After the dialog returns a response identifier, you need to make sure to call dialog.destroy(), or it will cause a memory leak. GTK+ makes sure all of the dialog’s children are destroyed, but you need to remember to initiate the process.
By calling dialog.destroy(), all of the parent’s children are destroyed and its reference count drops. When an object’s reference count reaches zero, the object is finalized, and its memory freed.
The Gtk.Image Widget
Listing 6-1 introduces another new widget called Gtk.Image. Images can be loaded in a wide variety of ways, but one advantage of Gtk.Image is that it displays the named image “image-missing” if the loading has failed. It is also derived from Gtk.Widget, so it can be added as a child of a container unlike other image objects, such as Gdk.Pixbuf.
Gtk.IconSize.INVALID: Unspecified size
Gtk.IconSize.MENU: 16×16 pixels
Gtk.IconSize.SMALL_TOOLBAR: 18×18 pixels
Gtk.IconSize.LARGE_TOOLBAR: 24×24 pixels
Gtk.IconSize.BUTTON: 24×24 pixels
Gtk.IconSize.DND: 32×32 pixels
Gtk.IconSize.DIALOG: 48×48 pixels
As you can see, theme Gtk.Image objects are usually used for smaller images, such as those that appear in buttons, menus, and dialogs, since theme images are provided in a discrete number of standard sizes. In Listing 6-1, the image was set to Gtk.IconSize.DIALOG or 48×48 pixels.
Gtk.Image automatically detects the image type of the file specified to new_from_file(). If the image cannot be loaded, it displays a broken-image icon. Therefore, this function never returns a None object. Gtk.Image also supports animations that occur within the image file.
You need to note that the Gtk.Image creates its own references to the Gdk.Pixbuf, so you need to release your reference to the object if it should be destroyed with the Gtk.Image.
Nonmodal Message Dialog
By calling dialog.run(), your dialog is always set as modal, which is not always desirable. To create a nonmodal dialog, you need to connect to Gtk.Dialog’s response signal.
A Nonmodal Message Dialog
Creating a nonmodal dialog is very similar to the previous example, except you do not want to call dialog.run(). By calling this function, a modal dialog is created by blocking the parent window’s main loop regardless of the dialog flags.
Tip
You can still create a modal dialog without using dialog.run() by setting the Gtk.DialogFlags.MODAL flag. You can then connect to the response signal. This function simply provides a convenient way to create modal dialogs and handle response identifiers within one function.
By connecting to Gtk.Dialog’s response signal, you can wait for a response identifier to be emitted. By using this method, the dialog is not automatically unreferenced when a response identifier is emitted. The response callback method receives the dialog, the response identifier that was emitted, and the optional data parameter.
One of the most important decisions you have to make when designing a dialog is whether it is modal or nonmodal. As a rule of thumb, if the action needs to be completed before the user can continue working with the application, then the dialog should be modal. Examples of this would be message dialogs, dialogs that ask the user a question, and dialogs to open a file.
If there is no reason why the user cannot continue working while the dialog is open, you should use a nonmodal dialog. You also need to remember that multiple instances of nonmodal dialogs can be created unless you prevent this programmatically, so dialogs that must have only one instance should be created as modal.
Another Dialog Example
This information is, of course, not actually changed within the user’s system; the new text is simply output to the screen. This example illustrates the fact that, regardless of the complexity of the dialog, the basic principles of how to handle response identifiers are still the only ones that are necessary.
Editing Information in a Dialog
The proper way to handle any modal dialog is to use the response identifiers, deriving the correct response based on the clicked button. Since there was only one response that needed to be deliberately detected, a conditional if statement was used in Listing 6-3.
Built-in Dialogs
There are many types of dialogs already built into GTK+. Although not all of the available dialogs are covered in this chapter, you are given a strong understanding of the concepts needed to use any built-in dialog. This section covers Gtk.MessageDialog, GtkAboutDialog, Gtk.FileChooserDialog , Gtk.FontChooserDialog, and Gtk.ColorChooserDialog.
Message Dialogs
Message dialogs give one of four types of informational messages: general information, error messages, warnings, and questions. This type of dialog decides the icon to display, the title of the dialog, and the buttons to add.
There is also a general type provided that makes no assumption as to the content of the message. In most cases, you will not want to use this, since the four provided types would fill most of your needs.
It is very simple to re-create the Gtk.MessageDialog widget. The first two examples implemented a simple message dialog, but Gtk.MessageDialog already provides this functionality, so you should not need to re-create the widget. Using Gtk.MessageDialog saves on typing and avoids the need to re-create this widget many times, since most applications make heavy use of Gtk.MessageDialog. It also provides a uniform look for message dialogs across all GTK+ applications.
Using a Gtk.MessageDialog
After the button in the main window is clicked, this example creates a new Gtk.MessageDialog.
The parent window can be set to None if necessary, but in most cases, a parent-child relationship should be established. If you do not set a parent widget, the message dialog will not be centered above the parent window.
You specify one or more dialog flags. Options for this parameter are given by the Gtk.DialogFlags enumeration that was used when creating custom dialogs in the previous three examples.
Unlike GTK+ 2.x, the 3.x Gtk.MessageDialog does not use any positional parameters. Instead, it uses keyword parameters exclusively. Also note that Gtk.MessageDialog does not use a new method. This is because Gtk.MessageDialog creates a subclass of Gtk.MessageDialog and the keywords determine what kind subclass is created.
Also note that the light bulb icon image is missing from the message dialog. This is due to philosophy changes in GTK+ 3.x. If you must have icons in your dialogs then you need to use Gtk.Dialog to hand create your dialogs.
Multiple buttons are supported by including a comma-separated list of buttons/response ids using the "buttons" keyword.
You have no control over the visual formatting of the message provided to Gtk.MessageDialog. If you would like to use the Pango Text Markup Language to format the message dialog’s text, you can leave out the "text" keyword from the Gtk.MessageDialog call. Then call set_markup(str) method with a string of Pango markup to set the text of the message.
It is possible to add a secondary text to the message dialog, which causes the first message to be set as bold with format_secondary_text(). The text string provided to this function should be similar to the format supported by the C printf().
This feature is very useful, because it allows you to give a quick summary in the primary text and go into detail with the secondary text.
About Dialogs
The Gtk.AboutDialog widget provides you with a simple way to provide the user with information about an application. This dialog is usually displayed when the item in the Help menu is chosen. However, since menus are not covered until Chapter 10, our example dialog is used as the top-level window.
By clicking the Credits button, the user is presented with any authors, documenters, translators, and artists that are provided. The License button pops up a new dialog that shows the given license content.
Using a Gtk.AboutDialog
Gtk.AboutDialog Option Values
Property | Description |
---|---|
program_name | The application’s name. |
version | The current version of the application the user is running. |
copyright | A short copyright string that should not span more than one or two lines. |
comments | A short description of the application that should not span more than one or two lines. |
license | License information that is displayed in a secondary dialog. Setting this to None hides the License button. |
web site | The home page URL of the application. |
web site_label | A label that is displayed instead of the URL. |
authors | A Python list of authors who have contributed code to the project. |
artists | A Python list of artists who have created graphics for the project. |
documenters | A Python list of documenters who have written documentation for the project. |
translator_credits | A string that specifies the translator(s) of the current language. |
logo | Usually loaded from a file, this Gdk.Pixbuf object is the application’s logo. |
Unlike author, artist, and documenter credits, the translator credits are only a single string. This is because the translator string should be set to the person that translated the language currently in use. Internationalization and gettext are not topics for this book. For more information, you should visit www.gnu.org/software/gettext .
Gdk.Pixbuf
GdkPixbuf is a class that contains information about an image stored in memory. It allows you to build images manually by placing shapes or pixels or to load a pre-built image from a file. The latter is preferred in most cases, so that is what is covered in this book.
Since GdkPixbuf is derived from GObject, it supports referencing. This means that the same image can be used in multiple locations in a program by increasing the reference count with ref(). Dereferencing GdkPixbuf objects (pixbufs) is performed automatically in almost all cases.
GdkPixbuf.InterpType.NEAREST: Sampling is performed on the nearest neighboring pixel. This mode is very fast, but it produces the lowest quality of scaling. It should never be used for scaling an image to a smaller size!
GdkPixbuf.InterpType.TILES: This mode renders every pixel as a shape of color and uses antialiasing for the edges. This is similar to using GdkPixbuf.InterpType.NEAREST for making an image larger or GdkPixbuf.InterpType.BILINEAR for reducing its size.
GdkPixbuf.InterpType.BILINEAR: This mode is the best mode for resizing images in both directions, because it has a balance between its speed and the quality of the image.
GdkPixbuf.InterpType.HYPER: While it is very high quality, this method is also very slow. It should only be used when speed is not a concern. Therefore, it should never be used for any application that the user would expect a fast display time. In one function call, GdkPixbuf.new_from_file_at_size() conveniently resizes the image immediately after it loads from the file.
Many other features are provided in the GdkPixbuf class, but only a few of these are covered, as needed. For further information on GdkPixbuf, you should reference the API documentation.
Gtk.FileChooser Dialogs
In the last chapter, you learned about Gtk.FileChooser and the Gtk.FileChooserButton widget. Recall that Gtk.FileChooser is not a widget, but an abstract class. Abstract classes differ from real classes, because they may not implement the methods they declare.
Gtk.FileChooserButton : The file chooser button was covered in the previous chapter. It allows the user to choose one file or folder by displaying a Gtk.FileChooser dialog when clicked.
Gtk.FileChooserDialog : This is the actual widget that allows the user to choose a file folder. It can also facilitate the creation of a folder or saving of a file. When you use Gtk.FileChooserDialog, you are actually using a file chooser widget packed into a Gtk.Dialog .
Gtk.FileChooserWidget: This is the actual widget that allows the user to choose a file folder. It can also facilitate the creation of a folder or saving of a file. When you use Gtk.FileChooserDialog , you are actually using a file chooser widget packed into a Gtk.Dialog .
You have already learned about Gtk.FileChooserButton and have used a file chooser to open one file and to select a directory. There are three other abilities provided by the file chooser widget. In the next three examples, you learn how to use a file chooser dialog to save a file, create a directory, and choose multiple files.
Saving Files
Using a Gtk.AboutDialog
Gtk.FileChooserAction .SAVE: The user is prompted to enter a file name and browse throughout the file system for a location. The returned file is the chosen path with the new file name appended to the end. Gtk.FileChooser provides methods that allow you to ask for confirmation if the user enters a file name that already exists.
Gtk.FileChooserAction .OPEN: The file chooser only allows the user to select one or more files that already exist on the user’s system. The user is able to browse throughout the file system or choose a bookmarked location.
Gtk.FileChooserAction.SELECT_FOLDER: This is very similar to the save action, because it allows the user to choose a location and specify a new folder name. The user can enter a new folder name that is created when the file chooser returns or click the Create Folder button, shown in Figure 5-6, which creates a new folder in the current directory.
Gtk.FileChooserAction .CREATE_FOLDER: This is very similar to the save action, because it allows the user to choose a location and specify a new folder name. The user can enter a new folder name that is created when the file chooser returns or click the Create Folder button, shown in Figure 5-6, which creates a new folder in the current directory.
Lastly, you have to provide a name/response ID list of buttons to add to the action area. In Listing 6-6, when the Cancel button is clicked, Gtk.ResponseType.CANCEL is emitted, and when the Save button is clicked, GTK_RESPONSE_ACCEPT is emitted.
Creating a Folder
Using a Gtk.AboutDialog
The full folder name of the dialog can be retrieved by using the same function that retrieved the file name in the previous example, get_filename() . The standard os.mkdir() method from the os module creates a folder in the specified location on all supported operating systems.
Selecting Multiple Files
Using A Gtk.FileChooserDialog to Select Multiple Files
Color Selection Dialogs
In the previous chapter, you learned about the Gtk.ColorButton widget, which allowed the user to select a color. After clicking that button, the user was presented with a dialog. Although not specified at the time, that dialog was a Gtk.ColorSelectionDialog widget.
Listing 6-9 contains a top-level window that has two buttons. When the first button is clicked, a modal Gtk.ColorSelectionDialog is created. The other button creates a nonmodal Gtk.ColorSelectionDialog. Each chooses global color and opacity values.
Using a Gtk.ColorSelectionDialog
Gtk.ColorSelectionDialog provides direct access to its four available child widgets. The first, colorsel is the Gtk.ColorSelection widget that facilitates color selection. The other three are an OK button, a Cancel button, and a Help button. By default, the Help button is hidden. You can use show() or the show_all() method to set it visible.
When opacity is turned on, the hexadecimal color value is sixteen digits long, four digits for each of the values: red, green, blue, and alpha. You must use colorsel.get_current_alpha() to retrieve its value from the color selection widget.
Font Selection Dialogs
Figure 6-9 is the result of running Listing 6-10.
Using a Gtk.FontSelectionDialog
The font selection dialog initialization function, Gtk.FontSelectionDialog(), returns a new Gtk.FontSelectionDialog widget with the specified title.
The dialog itself contains three buttons: OK, Apply, and Cancel. They emit the Gtk.ResponseType.OK, Gtk.ResponseType.APPLY, and Gtk.ResponseType.CANCEL signals respectively.
There is no need to create a modal dialog, because the font selection dialog is connected to a response signal.
If the user clicks the OK button, the user is presented with the selected font, and the dialog is destroyed. By clicking Apply, the selected font is presented to the user, but the dialog is not destroyed. This allows you to apply the new font so the user can view the changes without closing the dialog.
The font selection widget contains a Gtk.Entry widget that allows the user to preview the font. By default, the preview text is set to “abcdefghijk ABCDEFGHIJK”. This is somewhat boring, so I decided to reset it to “GTK+ 3 Development With Python”, the title of this book.
The last methods provided by Gtk.FontSelectionDialog() allow you to set and retrieve the current font string. The font string used by dialog.set_font_name() and dialog.get_font_name() is in the same format that we parsed with Pango.FontDescription in the previous chapter.
Dialogs with Multiple Pages
With the release of GTK+ 2.10, a widget called Gtk.Assistant was introduced. Gtk.Assistant makes it easier to create dialogs with multiple stages, because you do not have to programmatically create the whole dialog. This allows you to split otherwise complex dialogs, into steps that guide the user. This functionality is implemented by what are often referred to as wizards in various applications.
The Gtk.Assistant Widget
Creating Gtk.Assistant Pages
Page title: Every page should have a title, so the user knows what it is for. Your first page should be an introductory page that tells the user information about the assistant. The last page must be a summary or confirmation page that makes sure the user is ready to apply the previous changes.
Header image: In the top panel, you can display an optional image to the left of the title. This is often the application’s logo or an image that complements the assistant’s purpose.
Side image: This optional image is placed along the left side of the assistant beside the main page content. It is used for aesthetic appeal.
Page type: The page type must always be set, or it defaults to Gtk.AssistantPageType.CONTENT. The last page must always be a confirmation or summary page. You should also make the first page an introductory page that gives the user information about what task the assistant performs.
Gtk.AssistantPageType.CONTENT: This type of page has general content, which means it is used for almost every page in the assistant. It should never be used for the last page in an assistant.
Gtk.AssistantPageType.INTRO: This type of page has introductory information for the user. This should only be set for the first page in the assistant. Although not required, introductory pages give the user direction; they should be used in most assistants.
Gtk.AssistantPageType.CONFIRM: The page allows the user to confirm or deny a set of changes. It is typically used for changes that cannot be undone or may cause something to break if not set correctly. This should only be set for the last page of the assistant.
Gtk.AssistantPageType.SUMMARY: The page gives a summary of the changes that have occurred. This should only be set for the last page of the assistant.
Gtk.AssistantPageType.PROGRESS: When a task takes a long time to complete, this blocks the assistant until the page is marked as complete. The difference between this page and a normal content page is that all of the buttons are disabled and the user is prevented from closing the assistant.
Caution
If you do not set the last page type as Gtk.AssistantPageType.CONFIRM or Gtk.AssistantPageType.SUMMARY, your application will abort with a GTK+ error when computing the last button state.
"apply": This signal is emitted when the Apply button or Forward button clicks any assistant page.
"cancel": This signal is emitted when the Cancel button clicks any assistant page.
"close": This signal is emitted when the Close button or Apply button on the last page in the assistant is clicked.
"prepare": Before making a new page visible, this signal is emitted so that you can do any preparation work before it is visible to the user.
You can connect to all Gtk.Assistant signals with assistant.connect() or any other signal connection function provided by GLib . Excluding "prepare", the callback methods for Gtk.Assistant signals receive the assistant and the user data parameter. The callback method for the prepare signal also accepts the child widget of the current page.
On every page, a Cancel button is displayed in addition to a few others. On pages other than the first one, a Back button is displayed that is always sensitive. This allows you to visit the previously displayed page and make changes.
Note
The page that is visited when the user clicks the Back button is not always the previous page according to the page index. It is the previously displayed page, which may be different based on how you defined the page flow of your assistant.
On every page except the last, a Forward button is placed, which allows the user to move to the next page. On the last page, an Apply button is displayed that allows the user to apply the changes. However, until the page is set as complete, the assistant sets the Forward or Apply button as insensitive. This allows you to prevent the user from proceeding until some action is taken.
In Listing 6-11, the first and last pages of the assistant were set as complete, because they were merely informative pages. This is the case in most assistants, since they should begin with an introduction page and end with a confirmation or summary page.
The other two pages are where it becomes interesting. On the second page, we want to make sure that the user cannot proceed until text is entered in the Gtk.Entry widget. It would seem that we should just check when text has been inserted and be done with it.
However, what happens if the user deletes all of the text? In this case, the forward button should be disabled yet again. To handle both of these actions, you can use Gtk.Editable’s changed signal. This allows you to check the current state of the text in the entry upon every change, as in Listing 6-11.
On the third page, we want to enable the forward button only when the check button is active. To do this, we used the toggled signal of Gtk.ToggleButton to check the current state of the check button. Based on this state, the forward button’s sensitivity was set.
The fourth page has a type of Gtk.AssistantPageType.PROGRESS, which disables all actions until the page is set as complete. The user is instructed to click a button, which begins the process of filling a Gtk.ProgressBar widget 10 percent every second. When the progress bar is filled, the page is set as complete.
Gtk.ProgressBar
The Gtk.Assistant example introduced another new widget called Gtk.ProgressBar. Progress bars are a simple way to show how much of a process has been completed and is useful for processes that take a long time to handle. Progress bars give the user a visual cue that progress is being made, so they do not think the program has frozen.
You may also want to display text that can complement the progress bar. In the preceding example, progress.set_text() displayed the percent complete statistic, which is superimposed on the progress bar widget.
By setting the pulse step to 0.1, the progress bar fills up in the first ten steps and clears itself in the next ten. This process continues for as long as you continue pulsing the progress bar.
Page Forward Methods
There are times that you may want to skip to specific assistant pages if conditions are correct. For example, let’s assume your application is creating a new project. Depending on the chosen language, you want to jump to either the third or fourth page. In this case, you want to define your own Gtk.AssistantPageFunc method for forward motion.
Note
By returning –1 from a page forward function, the user is presented with a critical error and the assistant will not move to another page. The critical error message will tell the user that the page flow is broken.
In the assistant.forward() method, flow is changed based on the Boolean value returned by the fictional function decide_next_page(). In either case, the last page is page 4. If the current page is not within bounds, –1 is returned, so an exception is thrown by GTK+.
While this Gtk.Assistant example is very simple, implementations of this widget can become very complex as they expand in number of pages. This widget could be re-created with a dialog, a Gtk.Notebook with hidden tabs, and a few buttons. (I have had to do that very thing multiple times!), but it makes the process a lot easier.)
Test Your Understanding
In the exercise for this chapter, you are creating custom dialogs of your own. Each of the dialogs is an implementation of a type of file chooser dialog. However, you are embedding a Gtk.FileChooserWidget into a Gtk.Dialog to re-create the functionality of the built-in dialogs.
Exercise 1: Implementing File Chooser Dialogs
Your dialog implements a Gtk.FileChooserAction .SAVE file chooser dialog. The chosen file name should be printed to the screen.
Your dialog implements a Gtk.FileChooserAction.CREATE_FOLDER file chooser dialog. The new folder name should be printed to the screen. You have to manually create the new folder with a Python function.
Your dialog implements a Gtk.FileChooserAction.OPEN file chooser dialog. The chosen file names should be printed to the screen.
Your dialog implements a Gtk.FileChooserAction .SELECT_FOLDER file chooser dialog. The chosen folder path should be printed to the screen.
You need to set each of the dialogs to a decent size so that the entire content is visible to the user. If you get stuck during this exercise, you can find a solution in Appendix D.
Summary
In this chapter, you learned how to create your own custom dialogs. To do this, you need to first initialize the dialog. Then, action area buttons need to be added as well as the main content to the dialog’s vertical Gtk.Box.
Dialogs can be created as modal or nonmodal. A modal dialog created with dialog.run() blocks the user from interacting with the parent window until it is destroyed by creating a main loop for the dialog. It also centers the dialog above its parent window. Nonmodal dialogs allow the user to interact with any other window in the application and will not force focus on the dialog.
Message dialog (Gtk.MessageDialog): Provides a general message, error message, warning, or simple yes/no question to the user.
About dialog (Gtk.AboutDialog): Shows information about the application, including version, copyright, license, authors, and others.
File chooser dialog ( Gtk.FileChooserDialog ): Allows the user to choose a file, choose multiple files, save a file, choose a directory, or create a directory.
Color selection dialog (Gtk.ColorSelectionDialog): Allows the user to choose a color along with an optional opacity value.
Font selection dialog (Gtk.FontSelectionDialog): Allows the user to choose a font and its size and style properties.
The last section of this chapter showed you a widget called Gtk.Assistant, which was introduced in GTK+ 2.10. It allows you to create dialogs with multiple stages. It is important to note that assistants are not actually a type of Gtk.Dialog widget but are directly derived from the Gtk.Window class. This means that you have to handle these by connecting signals in the main loop instead of calling dialog.run().
You now have a firm understanding of many important aspects of GTK+. The Chapter 9 explains the multiline text entry widget called Gtk.TextView. Other topics include the clipboard and the Gtk.SourceView library.