20. Glade and Gtk.Builder

The Gtk.Builder class offers you the opportunity to design user interfaces without writing a single line of code. This is possible through describing the interface by a XML file and then loading the XML description at runtime and create the objects automatically, which the Builder class does for you. For the purpose of not needing to write the XML manually the Glade application lets you create the user interface in a WYSIWYG (what you see is what you get) manner

This method has several advantages:

  • Less code needs to be written.
  • UI changes can be seen more quickly, so UIs are able to improve.
  • Designers without programming skills can create and edit UIs.
  • The description of the user interface is independent from the programming language being used.

There is still code required for handling interface changes triggered by the user, but Gtk.Builder allows you to focus on implementing that functionality.

20.1. Creating and loading the .glade file

First of all you have to download and install Glade. There are several tutorials about Glade, so this is not explained here in detail. Let’s start by creating a window with a button in it and saving it to a file named example.glade. The resulting XML file should look like this.

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkButton" id="button1">
        <property name="label" translatable="yes">button</property>
        <property name="use_action_appearance">False</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
        <property name="use_action_appearance">False</property>
      </object>
    </child>
  </object>
</interface>

To load this file in Python we need a Gtk.Builder object.

builder = Gtk.Builder()
builder.add_from_file("example.glade")

The second line loads all objects defined in example.glade into the Builder object.

It is also possible to load only some of the objects. The following line would add only the objects (and their child objects) given in the tuple.

# we don't really have two buttons here, this is just an example
builder.add_objects_from_file("example.glade", ("button1", "button2"))

These two methods exist also for loading from a string rather than a file. Their corresponding names are Gtk.Builder.add_from_string() and Gtk.Builder.add_objects_from_string() and they simply take a XML string instead of a file name.

20.2. Accessing widgets

Now that the window and the button are loaded we also want to show them. Therefore the Gtk.Window.show_all() method has to be called on the window. But how do we access the associated object?

window = builder.get_object("window1")
window.show_all()

Every widget can be retrieved from the builder by the Gtk.Builder.get_object() method and the widget’s id. It is really that simple.

It is also possible to get a list of all objects with

builder.get_objects()

20.3. Connecting Signals

Glade also makes it possible to define signals which you can connect to handlers in your code without extracting every object from the builder and connecting to the signals manually. The first thing to do is to declare the signal names in Glade. For this example we will act when the window should be closed and when the button was pressed, so we give the name “onDeleteWindow” to the “delete-event” signal of the window and “onButtonPressed” to the “pressed” signal of the button. Now the XML file should look like this.

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <!-- interface-requires gtk+ 3.0 -->
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <signal name="delete-event" handler="onDeleteWindow" swapped="no"/>
    <child>
      <object class="GtkButton" id="button1">
        <property name="label" translatable="yes">button</property>
        <property name="use_action_appearance">False</property>
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="receives_default">True</property>
        <property name="use_action_appearance">False</property>
        <signal name="pressed" handler="onButtonPressed" swapped="no"/>
      </object>
    </child>
  </object>
</interface>

Now we have to define the handler functions in our code. The onDeleteWindow should simply result in a call to Gtk.main_quit(). When the button is pressed we would like to print the string “Hello World!”, so we define the handler as follows

def hello(button):
    print "Hello World!"

Next, we have to connect the signals and the handler functions. The easiest way to do this is to define a dict with a mapping from the names to the handlers and then pass it to the Gtk.Builder.connect_signals() method.

handlers = {
    "onDeleteWindow": Gtk.main_quit,
    "onButtonPressed": hello
}
builder.connect_signals(handlers)

An alternative approach is to create a class which has methods that are called like the signals. In our example the last code snippet could be rewritten as:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Handler:
    def onDeleteWindow(self, *args):
        Gtk.main_quit(*args)

    def onButtonPressed(self, button):
        print("Hello World!")

builder = Gtk.Builder()
builder.add_from_file("builder_example.glade")
builder.connect_signals(Handler())

20.4. Example

The final code of the example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
from gi.repository import Gtk

class Handler:
    def onDeleteWindow(self, *args):
        Gtk.main_quit(*args)

    def onButtonPressed(self, button):
        print("Hello World!")

builder = Gtk.Builder()
builder.add_from_file("builder_example.glade")
builder.connect_signals(Handler())

window = builder.get_object("window1")
window.show_all()

Gtk.main()