© W. David Ashley and Andrew Krause 2019
W. David Ashley and Andrew KrauseFoundations of PyGTK Developmenthttps://doi.org/10.1007/978-1-4842-4179-0_11

11. Dynamic User Interfaces

W. David Ashley1  and Andrew Krause2
(1)
AUSTIN, TX, USA
(2)
Leesburg, VA, USA
 

By now, you have learned a great deal about GTK+ and its supporting libraries, and you are able to create fairly complex applications. However, manually writing all of the code to create and configure the widgets and behavior for these applications can quickly become tedious.

The Glade user interface builder removes the need for you to write all of that code by allowing you to design your UI graphically. It supports the GTK+ library of widgets as well as various widgets from the GNOME libraries. User interfaces are saved as XML files, which can dynamically build your application’s user interface.

The last part of this chapter covers Gtk.Builder, a library that can dynamically load the XML files. Gtk.Builder creates all the necessary widgets and allows you to connect any signals defined in Glade.

Note

This chapter covers the user interface of Glade that is current at the time of this writing. It is possible that this may change in the future, but any changes should be an easy transition from the instructions provided in this chapter.

In this chapter, you learn the following.
  • Issues you should keep in mind when designing graphical user interfaces (GUIs)

  • How to design custom graphical user interfaces with Glade

  • How to dynamically load Glade user interfaces with Gtk.Builder

User Interface Design

In this chapter, you are going to learn how to use Glade 3 and Gtk.Builder to implement dynamic user interfaces. However, it is prudent to first learn a few concepts that you should keep in mind when designing graphical user interfaces. These concepts can help you to avoid confusing and frustrating users in the future.

You also have to realize that, while you know how to use your application because you designed it, you need to do as much as possible to help the user make sense of it. Whether the user is an expert or a novice, each user should be able to use your application with the shortest possible learning curve. That said, the following sections include many tips and design decisions to help you achieve this level of intuitiveness. They also improve the maintainability of your application.

Know Your Users

When designing a user interface, the most important thing to consider is your audience. Are they all experienced with the task at hand, or will some need more help than others? Can you model your user interface after one that they are already familiar with, or is this something completely new?

One of the biggest possible mistakes is to make rash generalizations about your users’ skill level. You may think that the way you lay out your application makes sense, but that is because you designed it. You should place yourself in the users’ position, understanding they will have no prior knowledge about how to use your application.

To avoid confusion, take time to study similar applications, taking note of what design decisions seem successful and which cause problems. For example, if you are creating an application to be used in the GNOME desktop environment, you should check out the GNOME Human Interface Guidelines ( http://developer.gnome.org ), which can help you lay out a design that is used for other compliant applications.

Another thing to consider when designing a user interface is accessibility. Users may have vision problems that could inhibit them from using an application. The Accessibility Toolkit provides many facilities for GTK+ applications to make them compatible with screen readers. GTK+ also relies heavily on themes, which is why you should avoid setting the font, when possible, or provide the user with a way to change it.

Your language is another consideration when designing the user interface. First, you should always use jargon that is familiar to the users. For example, you are free to use mathematical terms in an engineering application, but you should not do so in a web browser.

Many applications are translated into other languages when they become popular, which may cause problems if you use words or images that could be offensive in other cultures.

Keep the Design Simple

Once you know your audience, it becomes a lot simpler to design an effective user interface, but you can still run into problems if the interface is too difficult or cluttered. Always try to reduce the number of widgets on the screen to a reasonable number.

For example, if you need to provide many choices to the user where only one can be selected, you might be tempted to use a lot of radio buttons. However, a better solution may be to use a Gtk.ComboBox, which significantly decreases the number of required widgets.

The Gtk.Notebook container is extremely useful for grouping similar option groups that would otherwise clutter a huge page. In many applications, this widget groups widgets that relate or depend on each other into a preferences dialog.

Menu layout is also another problematic area, because it is not always done in a sensible manner. When possible, you should use standard menus, such as File, Edit, View, Help, Format, and Window. These menus are familiar to users who are experienced with computing, and users expect them. Because of this, these menus should contain standard items as well. For example, the File menu should contain items for manipulating files, printing, and exiting the application. You should investigate how other applications lay out their menu items if you are not sure where to place a particular item.

Repetitive jobs, or those that the user performs often, should always be made quick and easy. There are multiple ways to do this. The most important is to provide keyboard accelerators for many actions —pressing Ctrl+O on the keyboard is a lot faster than clicking the File menu and the Open menu item.

Note

Whenever possible, you should always use standard keyboard accelerators, such as Ctrl+X for cutting and Ctrl+N for creating something new. This significantly decreases the initial learning curve for users of your application. In fact, some keyboard accelerators are already built into many widgets, such as Ctrl+X for cutting the selection in text widgets.

It may take some time for your users to become accustomed to keyboard accelerators, which is why toolbars are also extremely useful for repetitive options. You need to find a balance between placing too few and too many items on a toolbar, though. A cluttered toolbar scares and confuses the user, but a toolbar with too few items is useless. If you have a large number of items that users might want on toolbars, it would make sense to allow the users to customize the toolbars themselves.

Always Be Consistent

Consistency is important when designing a graphical user interface, and GTK+ makes this extremely easy. First, GTK+ provides many stock items that should always be used in favor of homegrown items where possible. The user will already be familiar with the icons for the stock items and will know how to use them.

Caution

Stock items can be very dangerous if you do not use them correctly. You should never use a stock item for an action for which it was not originally intended. For example, you should not use GTK_STOCK_REMOVE icon for a subtraction operation just because it looks like a “minus sign.” The icons are defined by the user’s theme; they may not always look the way you assume.

Speaking of themes, you should fall back on the settings provided by a theme whenever possible. This helps you create a consistent look—not only throughout your application but across the entire desktop environment. Since themes are applied to all applications throughout a desktop, your application is consistent with most other applications that the user runs.

In those few cases where you do need to deviate from the defaults provided by the user’s theme, you should always give the user a way to change the settings or to just use the system defaults. This is especially important when dealing with fonts and colors, because your changes can render your application unusable with some themes.

Another advantage of consistency is that the user learns how to use your application much faster. The user needs to learn only one design instead of many. If you do not use a consistent layout for your application and supplemental dialogs, the user is presented with a brand-new adventure with every new window.

Keep the User in the Loop

One thing that can turn off a user of your application very quickly is if it is not responsive for a long period of time. Most computer users are accustomed to a bug or two, but if your application is processing information and remains unresponsive for quite a while, the user may give up.

To avoid this, there are two possible solutions. The first is to make your application more efficient. However, if your application is not to blame, or there is no way to make it more efficient, you should use progress bars. A progress bar tells the user that your application is still working. Just make sure to update your progress bar! If you do not know how long the process will take, another option would be to pulse the progress bar and provide messages that update the user on the process’s progress.

Also, remember the following loop from Chapter 3.
while Gtk.events_pending():
    Gtk.main_iteration()

This loop makes sure that the user interface is updated, even when the processor is busy processing another task. If you do not update the user interface during a CPU-intensive process, the application may be unresponsive to the user until it is finished!

You should also provide your users with feedback when actions are performed. If a document is being saved, you should mark it as unmodified or display a message in the status bar. If you do not provide feedback to the user when an action is performed, it may be assumed that the action was not performed.

Message dialogs are a very useful way to provide feedback, but they should be used only when necessary. The user will become frustrated if message dialogs appear too often, which is why only critical errors and warnings should be reported this way.

We All Make Mistakes

Whether you are an expert or a novice, we all make mistakes. Because of this, you should always forgive your users. After all, everyone has at one time or another pressed an incorrect button that resulted in losing a large amount of work. In a properly designed application, this should never occur.

For basic actions that cannot be easily undone by the user, you should provide the ability to undo the action. For example, these basic actions could include deleting an item from our Grocery List application or moving text within a text view.

For actions that cannot be undone, you should always provide a confirmation dialog. It should explicitly state that this action cannot be undone and ask whether the user wants to continue. For example, you should always ask the user whether the application should be closed when there are documents with unsaved changes. People have been using software for years and have come to expect a confirmation dialog box for actions that cannot be undone.

The Glade User Interface Builder

One factor that can make or break a GUI toolkit is whether it can rapidly deploy applications. While the user interface is extremely important to the success of an application, it should not be the most consuming aspect of the development process.

Glade is a tool that allows you to quickly and efficiently design graphical user interfaces so that you can move onto other aspects of your code. User interfaces are saved as an XML file that describes the widget structure, the properties of each widget, and any signal handlers you associated with each. Gtk.Builder can then load the user interface file to dynamically build it on application load. This allows you to alter the user interface aesthetically without the need to recompile the application.

Note

Older versions of Glade allowed you to generate source code instead of saving the user interface in an XML file. This method is deprecated, because it is difficult to manage when you want to change your user interface. Therefore, you should follow the method provided in this chapter.

You need to realize from the start what Glade is and what it is not. Glade designs the user interface of an application, set up signals that are associated with callback methods implemented in your code, and take care of common widget properties. However, Glade is not a code editor or an integrated development environment. The files it outputs must be loaded by your application, and you must implement all of the callback methods in your code. Glade is just meant to simplify the process of initializing your application’s graphical user interface and connecting signals.

Tip

Glade 3.22.1, the version used in this book, now allows integrated development environments, such as Anjuta, to embed it into their user interfaces. These IDEs provide a complete, start-to-finish solution for deploying GTK+ applications.

Another advantage of Glade is that, since the user interfaces are stored as XML files, they are independent of the language. Any language that has wrapped the functionality provided by Gtk.Builder can load user interfaces. This means that the same graphical user interface designer can be used regardless of the programming language you choose.

Before continuing with the rest of this chapter, you should install Glade and the development package for Gtk.Builder from your operating system’s package manager. Alternatively, you can download and compile the sources from glade. gnome.org .

Also, you should make sure to follow along and create this application while reading the rest of the chapter. This gives you a chance to learn your way around the Glade 3 application, so you can get as much practice as possible while you have this book to guide you.

The Glade Interface

When you launch Glade for the first time, you see a main window with three panes: the main window tree view, the widget palette, and the widget property editor. Figure 11-1 is a screenshot of the main Glade application window with a project opened from the FileBrowser.glade.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig1_HTML.jpg
Figure 11-1

The Glade main window

The main tree view window facilitates Glade project management. The Main Window Title Bar shows a list of the currently open projects, allowing you to switch among them. The left pane also includes the widget tree view, which shows the widget containment of the project with focus.

The widget tree view shows the parent-to-child container relationships within a project. It is possible to have multiple top-level widgets. However, in Figure 11-1 window is the only top-level widget of the FileBrowser.glade.

This pane is where you specify project options, save the project, and load existing projects. The Popup menus in this window also provide many other options that can help you when working with projects, such as undoing and redoing actions.

Note

If you decide to work with Glade 2 instead of Glade 3, make sure to save often. Undo and redo support was not implemented in the older versions of Glade, and it is very frustrating if you accidentally overwrite an hour of work with one wrong mouse click!

The middle pane shown when you launch Glade 3 has buttons for selecting widgets from a widget palette, which lists all of the widgets available to you for designing your applications. A screenshot of the one of the widget palettes is shown in Figure 11-2.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig2_HTML.jpg
Figure 11-2

A Glade widget palette

By default, there are five categories of widgets that can be displayed: top-level widgets, containers, widgets used for control, display widgets, and composite and depreciated widgets. You should not use any widgets in the GTK+ Obsolete list in new applications, because they are depreciated and may be removed in future releases.

In addition to the default categories of widgets, you may find other categories that include additional widget libraries. These include widgets added for the GNOME libraries or other custom widget libraries.

Through the View menu, you can change the layout of the widget palette. Figure 11-2 shows a widget palette that is set to show both icons and text. However, you can show only text or only icons depending on what style you are most comfortable with.

To add a new top-level widget to the widget layout pane, all you need to do is click the icon of the desired widget in the Toplevels section. A new top-level widget is then displayed and added to the widget tree in the left pane. To add non-top-level widgets, you need to first click the icon of the desired widget and then click your mouse where the widget should be placed. You must click an empty cell in a container widget for the non-top-level widget to be inserted into the user interface.

Creating the Window

In this chapter, you are going to be creating a simple file browser application with Glade and Gtk.Builder. You begin by creating a new project by clicking on the new project button at the top of the main Glade window or by using the blank project created for you when the application loads. You can open an existing project by clicking on the Open button at the top of the main Glade window if you return to this tutorial at a later time.

After you have a blank project, you can begin by creating a new top-level Gtk.Window by clicking the Window icon in the Toplevels widget palette. In the new window, you see a mesh pattern in the interior of the widget, as displayed in Figure 11-3. This pattern designates a region where a child widget can be added to a container. After selecting a non-top-level widget from the widget palette, you must click this region to add the widget to the container. Follow this method for adding all non-top-level widgets.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig3_HTML.jpg
Figure 11-3

The Default Gtk.Window widget

After you create the top-level window, you notice changes in the content of the widget Properties pane, shown in Figure 11-4. In this pane, you can customize all of the properties of each widget that is supported in Glade.

Note

While Glade allows you to edit many widget properties, some actions simply have to be performed in the code. Therefore, you should not view Glade as a replacement for everything that you have learned thus far in the book. You are still doing a lot of GTK+ development in most applications.

The widget Properties window displayed in Figure 11-4 has a complete list of the various options. The pane is divided into sections, which categorize the basic options that are specific to the widget type that is currently selected. For example, the Gtk.Window widget allows you to specify the window’s type, title, ability to be resized, default size, and so on.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig4_HTML.jpg
Figure 11-4

The widget properties pane

The ID field, which is scrolled beyond the bounds of the scrolled window in Figure 11-4 gives a unique name to the widget. Glade automatically assigns a name to each widget that is unique for the current project, but these are generic names. If you plan to reference a widget from within your application, you should give it an ID that means something. It can easily become confusing when you have to load three Gtk.TreeView3 widgets named treeview1, treeview2, and treeview3!

The Packing tab provides basic information about how the widget reacts to changes in the size of its parent widget, such as expanding and filling. Common properties are those provided by Gtk.Widget and are available to all widgets. For example, you can provide a size request in this tab.

Note

Packing options are a bit unintuitive when first working with Glade, because properties are set by the child instead of the parent container. For example, packing options for the children of a Gtk.Box are provided in the Packing tab of the children themselves instead of the parent container.

The Signals tab allows you to define signals for each widget that is connected by Gtk.Builder. Lastly, the Accessibility tab, designated by the handicapped symbol, gives options that are used for accessibility support.

As you will recall from the first example in this book, an empty Gtk.Window widget is not of any use except for illustrating how to create one. Since the file browser needs multiple widgets packed into the main window for this application, the next step is to add a vertical box container. Select the Box widget from the palette and click inside the grid pattern of window to insert a Gtk.Box widget into the window. You can then use the Properties pane to adjust the orientation of the box (vertical or horizontal) and the number of panes the Gtk.Box contains. Figure 11-5 shows the adjustments necessary for the Gtk.Box properties.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig5_HTML.jpg
Figure 11-5

The Default Gtk.Window widget

By default, three cells are created to hold child widgets, but you can change this to any number of items greater than zero. The default of three is how many child widgets we need.

By default, a Gtk.Box has a vertical orientation but you can change the orientation to horizontal if needed.

Note

Do not worry if you are not sure how many widgets the container will hold. You can add or remove cells in the General tab in the widget Properties pane. You can then change the position of a widget within the box under the Packing tab. You are also still able to edit the user interface with your code after it is built by Gtk.Builder!

After adding the vertical box, you see three separate, empty container meshes; notice the changes in the Properties pane and the widget tree view pane. To these meshes, we will add a toolbar, an address bar, and a tree view.

Adding a Toolbar

The old handle box widget has long been deprecated since most of the widgets it was meant to contain have been enhanced to dynamically hide their content. The Gtk.Toolbar is one of the widgets that has been enhanced in this way. That means we can directly add the toolbar to the vertical Gtk.Box we added to the main window previously.

When the toolbar widget is added it only appears as a thin strip in the top pane of the vertical box. This is because it does not yet contain any buttons. And the method to add buttons to the toolbar is not immediately obvious. To add buttons to the toolbar right-click on the Gtk.Toolbar entry in the Glade tree view pane and a pop-up menu labeled Edit... appears, which then shows the dialog in Figure 11-6.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig6_HTML.jpg
Figure 11-6

The toolbar editor

The toolbar editor allows you to add any supported type of item to a toolbar. To add a new item, you need only to click the Add button. This presents you with a pane in the editor dialog with which you can modify the new button’s properties. Be careful here as your version of Glade may present you the option of using stock buttons. Stock items have all been deprecated so you must create your own custom buttons instead.

After you add a new tool button, the next step is to choose what type of widget it should be by selecting an option from the Type combo box. The types of toolbar items included in the combo box are a generic tool button containing an image and a label, toggles, radio buttons, menu tool buttons, tool items, and separators. When you select a new type, the dialog immediately changes to allow you to edit properties for the chosen type.

For example, in Figure 11-6 the selected tool button is of the type Gtk.MenuToolButton. Every toolbar item gives you the option of whether it should be visible when the toolbar is horizontal or vertical. This allows you to hide the toolbar item when the toolbar has a vertical orientation but show it to the user when the toolbar is horizontal.

Menu tool buttons also allow you to choose a label and image to display in the tool item. An image can be a stock image, an existing image file, or an identifier of a custom icon theme depending on what option you choose.

Along the bottom of the toolbar editor, you see a tree view that allows you to connect signals to each tool button. Glade provides a number of named callback methods for you to choose from that are based on the signal name and the name you gave the toolbar item. You are also able to enter your own custom callback method name. It is possible to specify data to pass to each method function through Gtk.Builder, so you can usually leave the “User data” parameter blank. In Figure 11-6 a callback method by the name on_back_clicked() was connected to Gtk.MenuToolButton’s "clicked" signal.

When you load the user interface with Gtk.Builder, you have two choices for connecting the callback methods defined in the Glade file with those in your code. If you want to manually connect each callback method, you can name the signal handler whatever you choose, as long as the name is unique. However, Gtk.Builder provides a function that automatically connects all of the signals to the appropriate symbols in your executable or Python program. To use this feature, the callback method name you define in Glade must match the name of the function in your code!

The Packing tab includes options to determine padding around the widget, whether the packing is from the start or end of the box, and to determine the widget’s position within the container. These properties are exactly equivalent to the settings you used when adding child widgets to Gtk.Box with box.pack_start() and friends.

Tip

You should remember from Chapter 4 that a table was provided that illustrates what the expand and fill properties do to child widgets of a Gtk.Box widget. Glade is a perfect opportunity for you to experiment with packing options to gain a better understanding of how they affect the widget. Therefore, take a moment to experiment with the various packing options!

After completing the toolbar and fixing packing preferences, your application should look like Figure 11-7.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig7_HTML.jpg
Figure 11-7

The toolbar in action

The toolbar shown in Figure 11-7 contains two menu tool buttons used for moving forward and backward through the user’s browsing history. There are also tool buttons for moving to the parent directory, refreshing the current view, removing a file, moving to the home directory, and viewing file information. Each of these tool buttons is connected to a callback method that you must implement in your code for the application.

Completing the File Browser

The next step in creating our file browser is to create the address bar that shows the users the current location and allow them to enter a new location. This means that we need a horizontal box with three widgets, as shown in Figure 11-8. The three widgets are a label describing the content held in the Gtk.Entry widget, the Gtk.Entry widget that holds the current location, and a button that moves to the location when pressed.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig8_HTML.jpg
Figure 11-8

The file browser

To create the button in Figure 11-8 a horizontal Gtk.Box with two child widgets was added to the button: a Gtk.Image widget set to the GTK_STOCK_JUMP_TO stock image and a Gtk.Label widget named Go.

The last step is to add a Gtk.ScrolledWindow widget to the last cell in the vertical box and a Gtk.TreeView widget to that container. The completed file browser user interface is shown in Figure 11-9. However, we are not yet finished editing the application in Glade.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig9_HTML.jpg
Figure 11-9

The file browser

Making Changes

The file browser is completely designed, but now I have decided that it should include a Gtk.StatusBar widget along the bottom of the window! Making changes to the user interface can be tricky, so this section walks you through a few challenging actions.

The first step in adding the status bar is to extend the number of child widgets contained by the main vertical Gtk.Box widget. To do this, choose the vertical box from the widget tree view. In the Properties pane, you can increase the number of children with the “Number of items” property in the General tab. This adds a new empty space at the end of the vertical box into which you can add a status bar widget.

If you need to reorder the children of a vertical or horizontal box, you first need to select the widget you want to move. Then, under the Packing tab in the Properties pane, you can choose a new position by changing the value of its spin button. You are able to see the child widget moving to its new position as you change spin button’s value. The positions of surrounding child widgets are automatically adjusted to reflect the changes.

Another problematic task can result if you decide that you need to stuff a container into a location where another widget is already added. For example, let’s assume that you have decided to place a horizontal pane in place of the scrolled window in the file browser application. You first need to select the widget from the widget tree view in the main window and remove it by pressing Ctrl+X. After this, an empty box is displayed, in which you can add the horizontal pane. Next, select the pane where the scrolled window should be placed and press Ctrl+V.

Making changes to a user interface used to be a touchy topic with Glade 2, because it did not support undo and redo actions. It used to be very easy to make a mistake and lose hours of work by accidentally deleting your top-level widget, since you could not undo any actions. Now that Glade 3 includes undo and redo support, you do not have to worry as much.

Widget Signals

The last step for this application is to set up signals for all of the widgets. Figure 11-10 shows the Signals tab of the widget properties editor for the Go button. The Gtk.Button widget is connected to the clicked signal, which calls on_button_clicked() when emitted.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig10_HTML.jpg
Figure 11-10

A widget signal editor

In addition to the “clicked” signal, you need to connect to a few others. Each of the tool items should be connected to Gtk.ToolButton’s clicked signal with the exception of the separators. Also, you should connect the Gtk.Entry to activate, which is emitted when the user presses the Enter key when the entry has focus.

Note

This application is only a design for a simple file browser that is meant to show you how to design applications with Glade 3. The code needed for the application to be more than just a design is implemented in Chapter 14.

As for the tree view, you should connect it to row-activated. When a row is activated, the user is shown more information about the file, or it navigates to the chosen directory. A list of the widgets along with their signals and callback methods is provided in Table 11-1 so that you can easily follow along with this example.
Table 11-1

Widget Signals

Widget

Description

Signal

Callback Method

Gtk.Button

Go button

“clicked”

on_go_clicked()

Gtk.Entry

Location entry

“activate”

on_location_activate()

Gtk.MenuToolButtonBack

 

“clicked”

on_back_clicked()

Gtk.MenuToolButtonForward

 

“clicked”

on_forward_clicked()

Gtk.ToolButton

Up

“clicked”

on_up_clicked()

Gtk.ToolButton

Refresh

“clicked”

on_refresh_clicked()

Gtk.ToolButton

Home

“clicked”

on_home_clicked()

Gtk.ToolButton

Delete

“clicked”

on_delete_clicked()

Gtk.ToolButton

Information

“clicked”

on_info_clicked()

Gtk.TreeView

File browser

“row-activated”

on_row_activated()

Gtk.Window

Main window

“destroy”

on_window_destroy()

Creating a Menu

In addition to toolbars, it is possible to create menus in Glade 3. Figure 11-11 shows the menu bar editor, which is very similar to the toolbar editor. It supports normal menu items and those rendered with images, check buttons, radio buttons, and separators.
../images/142357_2_En_11_Chapter/142357_2_En_11_Fig11_HTML.jpg
Figure 11-11

The menu bar editor

Caution

The Glade 3.22.1 editor currently still uses Stock Items for Menu Items. All Stock Items are deprecated so you really should be using your own custom menu items, only this version of Glade does not support custom menu items. You may need to edit the XML produced by Glade to create your own custom entries.

You now know of three ways to create menus; this raises the question of which one is best. Every method has its advantages and disadvantages, so let’s take a look at each method.

You first learned how to create menus manually, molding each object to your needs. This method is good to use with smaller menus, because the code will not take up a lot of space and the implementation is located entirely in one place. However, if your menu grows in size or contains more than just basic items, the code can become tedious to maintain and take up a lot of space.

Next, you learned how to use Gtk.Builder with UI definitions to dynamically create menus. This method simplified menu creation, because you could define a large number of actions in a small amount of space. Also, since menus are constructed from UI definitions, allowing the user to edit a menu is extremely simple. This is clearly the preferred method of menu creation if you are not using Glade to design your application.

Glade also presents a very attractive method of menu creation, because after its initial design, maintenance is simple. It also requires no code to create the menu, since Gtk.Builder constructs it for you. However, one problem with this method is that it is not as easy to allow the user to alter the layout of menus and toolbars as with the UI file method.

One method that can easily be employed is to pack all of your widgets with respect to the end of the vertical box or whatever container you use as the child of the main window. Then, when your application loads, you can simply pack the menu created by Gtk.Builder into the window with box.pack_start(). Nevertheless, if you do not need to allow your users to customize the menu, it makes sense to do all menu creation through Glade.

Now that you are finished creating the user interface, you can save it as a FileBrowser.glade file, where project can be replaced by a name of your choice. This file can be loaded with respect to the location of the application or from an absolute path.

Using Gtk.Builder

After you design your application in Glade, the next step is to load the user interface with Gtk.Builder.

This GTK+ class parses the Glade user interface and creates all of the necessary widgets at runtime.

Gtk.Builder provides the methods necessary to create and hold the user interface loaded from an XML file. It can also connect signals added in the Glade file to callback methods within your application.

Another advantage of Gtk.Builder is that overhead is added only during initialization, and this is negligible compared to an interface created directly from code. After initialization, there is virtually no overhead added to the application. For example, Gtk.Builder connects signal handlers internally in the same way as your own code, so this requires no extra processing.

Since Gtk.Builder handles all of the widget initialization and the layout was already designed in Glade 3, the length of your code base can be significantly reduced. Take, for example, Listing 11-1, which would be significantly longer if you had to hand-code everything.
#!/usr/bin/python3
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
class SignalHandlers():
    def on_back_clicked(self, button ):
        pass
    def on_forward_clicked(self, button ):
        pass
    def on_up_clicked(self, button ):
        pass
    def on_refresh_clicked(self, button ):
        pass
    def on_home_clicked(self, button ):
        pass
    def on_delete_clicked(self, button ):
        pass
    def on_info_clicked(self, button ):
        pass
    def on_go_clicked(self, button ):
        pass
    def on_location_activate(self, button ):
        pass
    def on_row_activated(self, button ):
        pass
    def on_window_destroy(self, button ):
        pass
class Application(Gtk.Application):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, application_id="org.example.myapp",
                         **kwargs)
        self.window = None
    def do_activate(self):
        if not self.window:
            builder = Gtk.Builder()
            builder.add_from_file("./FileBrowser.glade")
            self.window = builder.get_object("main_window")
            self.add_window(self.window)
            builder.connect_signals(SignalHandlers())
            self.add_window(self.window)
        self.window.show_all()
if __name__ == "__main__":
    app = Application()
    app.run(sys.argv)
Listing 11-1

Loading the User Interface

Loading a User Interface

Loading a Glade user interface is done with builder.add_from_file(). This is the first Gtk.Builder method you should call, although it should be called after getting an instance of Gtk.Builder. It parses the user interface provided by the XML file, creates all of the necessary widgets, and provides facilities for translation. The only parameter needed by the builder.add_from_file() method is the path to your Glade project file.
builder = Gtk.Builder()
builder.add_from_file("./FileBrowser.glade")
Next, you need to fetch the "main_window", connect all the signals, and lastly add the window to the Gtk.Application class instance.
self.window = builder.get_object("main_window")
builder.connect_signals(SignalHandlers())
self.add_window(self.window)

The builder.get_object() needs one parameter which is the ID you assigned to the Gtk.Window main window in your Glade project. From this Gtk.Builder can determine all the child widgets that belong to the main window from reading the XML. It can then construct the window from the XML definition.

After constructing the main window, we need to assign all the signal handlers. Gtk.Builder can do this automatically if we supply a special Python class that contains nothing but the signal handler methods. The builder.connect_signals() method does this by supplying an instance of our signal handler class to it as a parameter.

Finally, we need to add the window constructed by Gtk.Builder to our Gtk.Application. This window now becomes controlled by our Gtk.Builder instance. While it is not a full Gtk.ApplicationWindow it acts very much like one as far as controlling the new window. Note that we use the window.show_all() to show the window instead of the window.present() method because our new window has no present() method.

It really is as simple as that. The File Browser window appears immediately and you are off and running. All that is left to do is fill all the signal handler methods, create the store for the Gtk.TreeView widget, build the window initialization code, and you have a working application.

Test Your Understanding

These two exercises are especially important for you to become a proficient GTK+ developer. It is not practical to programmatically design every aspect of large applications, because it takes too long.

Instead, you should be using Glade to design the user interface and Gtk.Builder to load that design and connect signals. By doing this, you are able to quickly finish the graphical aspects of your applications and get to the backend code that makes your applications work.

Exercise 1: Glade Text Editor

This exercise implements the text editor from the “Test Your Understanding” Exercise 1 section in Glade. The toolbar in the text editor should be implemented completely in Glade.

This exercise should not require extra coding if you still have the exercise solution from the previous chapter. You can also find the solution to “Test Your Understanding” section on the book’s web site at www.gtkbook.com . This exercise gives you a chance to learn your way around Glade 3 and test out many widget properties.

After you design an application with a toolbar, it is an easy transition to add a menu bar. In larger applications, you should provide both of these options to the user. In the following exercise, you add a menu bar to the text editor application.

Exercise 2: Glade Text Editor with Menus

You have implemented the text editor with a menu bar. In this exercise, redesign the application from that exercise using Glade and Gtk.Builder. First, you should implement the menu with Python and GTK+, which allows you to use both together. Second, you should implement the menu again in Glade.

As with the previous exercise, the solution for Exercise 2 is at www.gtkbook.com . Using the downloadable solution allows you skip coding the callback functions because you already did that in the previous chapter.

Summary

In this chapter, we took a short break from coding and looked into issues that you need to consider when designing a graphical user interface. In short, you must always keep your users in mind. You need to know what to expect of your users and cater to their needs in every aspect of the application.

Next, you learned how to design graphical user interfaces using Glade 3. The ability to quickly deploy the graphical aspects of an application is necessary when considering a GUI toolkit, and GTK+ has Glade to fill this need.

Glade allows you to design every aspect of your user interface, including widget properties, layout, and signal handlers. User interfaces are saved as readable XML files that describe the structure of your application.

After designing an application in Glade 3, you can dynamically load the user interface with Gtk.Builder. This GTK+ class parses the Glade user interface and creates all the necessary widgets at runtime. It also provides functions for connecting signal handlers declared in Glade to callback methods within your application.

In the next chapter, we are going to get back to coding and delve into the complexities of the GObject system. You learn how to create your own GObject classes by deriving new widgets and classes, as well as how to create a widget from scratch.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.157.142