Ebooks

Python Gtk tutorial

Python Gtk tutorial shows how to create GUI applications in Python using Gtk module.

GTK+

GTK+ is a multi-platform toolkit for creating graphical user interfaces. In is created in C language. GTK+ has been designed from the ground up to support a range of languages, including Python, Ruby, and Perl.

The GTK+ library is also called the GIMP Toolkit. Originally, the library was created while developing the GIMP image manipulation program. Since then, the GTK+ became one of the most popular toolkits under Linux and BSD Unix.

Python Gtk simple example

In the first application, we display a window on the screen. Gtk.Window is a toplevel window which can contain other widgets. In other words, it is a container. Windows normally have decorations that are under the control of the windowing system and allow the user to manipulate the window.

simple.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

win = Gtk.Window()
win.connect("destroy", Gtk.main_quit)
win.show()
Gtk.main()

The example shows a small window on the screen.

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

We import the Gtk module. The require_version() method ensures the namespace gets loaded with the given version. The gi.repository is the Python module for PyGObject. PyGObject (Python GObject introspection) contains Python bindings and support for gobject, glib, gtk and other Gnome libraries.

win = Gtk.Window()

An empty window is created.

win.connect("destroy", Gtk.main_quit)

This line ensures that the window is closed when we click on the Close button in the title bar.

win.show()

The show() window displays the window on the screen.

Gtk.main()

The main() method starts the event loop. The event loop waits for events such as mouse press, mouse move, or keyboard press events.

Python Gtk simple application
Figure: Python Gtk simple application

Python Gtk icon

An application icon is a small image which is usually shown in the titlebar of the application. Note that some environments might not show application icon, in some the application icons must be enabled.

icon.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    

        self.set_icon_from_file("web.png")

        self.set_title("Icon")
        self.set_default_size(280, 180)
        
        self.connect("destroy", Gtk.main_quit)


win = MyWindow()
win.show()
Gtk.main()

The web.png is located in the current working directory.

self.set_icon_from_file("web.png")

The set_icon_from_file() sets the application icon from the image file name.

self.set_default_size(280, 180)

The set_default_size() sets the default size of a window.

Application icon
Figure: Application icon

Python Gtk.Label

The Gtk.Label widget displays a small amount of text.

label.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

lyrics = """Meet you downstairs in the bar and heard
your rolled up sleeves and your skull t-shirt
You say why did you do it with him today?
and sniff me out like I was Tanqueray

cause you're my fella, my guy
hand me your stella and fly
by the time I'm out the door
you tear men down like Roger Moore

I cheated myself
like I knew I would
I told ya, I was trouble
you know that I'm no good"""

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    
        
        self.set_border_width(15)
        
        label = Gtk.Label(lyrics)
        self.add(label)

        self.set_title("You know I'm no Good")
        self.set_size_request(250, 180)
        
        self.connect("destroy", Gtk.main_quit)
        

win = MyWindow()
win.show_all()
Gtk.main()

The example shows lyrics on the window.

self.set_border_width(15)

The set_border_width() sets some margin space around the window.

label = Gtk.Label(lyrics)
self.add(label)

Gtk.Label is created and added to the window. The Gtk.Window is a simple container.

win.show_all()

We can show all widgets in one shot with show_all() method.

Gtk.Label
Figure: Gtk.Label

Python Gtk.Image

Gtk.Image dispalys an image. If the file is not loaded successfully, the image will contain a "broken image" icon.

image_example.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    

        self.set_border_width(10)

        image = Gtk.Image()
        image.set_from_file("redrock.png")

        self.add(image)

        self.set_title("Red Rock")
        self.connect("destroy", Gtk.main_quit)

win = MyWindow()
win.show_all()
Gtk.main()

The example displays a PNG image on the window.

image = Gtk.Image()
image.set_from_file("redrock.png")

Gtk.Image is created. The set_from_file() method sets the image from the given file name.

Python Gtk.Button

The Gtk.Button is used to trigger a callback function that is called when the button is pressed.

quit_button.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super().__init__()

        self.init_ui()


    def init_ui(self):

        grid = Gtk.Grid()
        self.add(grid)

        quitBtn = Gtk.Button(label="Quit")
        quitBtn.set_size_request(80, 30)
        quitBtn.connect("clicked", self.on_button_clicked)

        grid.attach(quitBtn, 0, 0, 1, 1)

        self.set_border_width(10)
        self.set_title("Quit button")
        self.set_default_size(280, 180)
        self.connect("destroy", Gtk.main_quit)

    def on_button_clicked(self, widget):
        Gtk.main_quit()

win = MyWindow()
win.show_all()
Gtk.main()

In the example, we have a button. When we press the button, the application terminates.

grid = Gtk.Grid()
self.add(grid)

We use the Gtk.Grid manager to organize our layout. The manager lays out widgets in a table.

quitBtn = Gtk.Button(label="Quit")
quitBtn.set_size_request(80, 30)

A Gtk.Button is created. The set_size_request() sets the minimum size of the button. The initial button size is quite small, therefore we increase its size.

quitBtn.connect("clicked", self.on_button_clicked)

When the button is clicked, it emits a clicked signal. With the connect() method we bind the signal to the on_button_clicked() callback method.

grid.attach(quitBtn, 0, 0, 1, 1)

With the attach() method, we place the button into the top-left cell of the grid.

def on_button_clicked(self, widget):
    Gtk.main_quit()

The callback method terminates the application with Gtk.main_quit().

Quit button
Figure: Quit button

Python Gtk.Fixed container

Gtk.Fixed widget is a container which puts child widgets at fixed positions and with fixed sizes, given in pixels. Gtk.Fixed performs no automatic layout management. Gtk.Fixed should be used only in specific cases.

fixed.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk, GdkPixbuf

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    
        
        self.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(6400, 6400, 6440))

        self.bardejov = GdkPixbuf.Pixbuf.new_from_file("bardejov.jpg")
        self.rotunda = GdkPixbuf.Pixbuf.new_from_file("rotunda.jpg")
        self.mincol = GdkPixbuf.Pixbuf.new_from_file("mincol.jpg")
        
        image1 = Gtk.Image()
        image2 = Gtk.Image()
        image3 = Gtk.Image()
        
        image1.set_from_pixbuf(self.bardejov)
        image2.set_from_pixbuf(self.rotunda)
        image3.set_from_pixbuf(self.mincol)
               
        fixed = Gtk.Fixed()
           
        fixed.put(image1, 10, 10)
        fixed.put(image2, 40, 160)
        fixed.put(image3, 170, 50)

        self.add(fixed)

        self.set_border_width(20)
        self.set_title("Fixed")
        
        self.connect("destroy", Gtk.main_quit)

win = MyWindow()
win.show_all()
Gtk.main()

The example shows three images at given fixed positions.

self.modify_bg(Gtk.StateType.NORMAL, Gdk.Color(6400, 6400, 6440))

We change the background colour of the window with modify_bg().

self.bardejov = GdkPixbuf.Pixbuf.new_from_file("bardejov.jpg")
self.rotunda = GdkPixbuf.Pixbuf.new_from_file("rotunda.jpg")
self.mincol = GdkPixbuf.Pixbuf.new_from_file("mincol.jpg")

image1 = Gtk.Image()
image2 = Gtk.Image()
image3 = Gtk.Image()

image1.set_from_pixbuf(self.bardejov)
image2.set_from_pixbuf(self.rotunda)
image3.set_from_pixbuf(self.mincol)

From three JPG images, we create three Gtk.Image widgets.

fixed = Gtk.Fixed()
   
fixed.put(image1, 10, 10)
fixed.put(image2, 40, 160)
fixed.put(image3, 170, 50)

The Gtk.Fixed container is created. Its put() method places the widget at the given coordinates.

self.add(fixed)

The Gtk.Fixed set to be the container for the Gtk.Window.

Fixed container
Figure: Fixed container

Python Gtk.CheckButton

Gtk.CheckButton a widget that has two states: on and off. The on state is visualised by a check mark.

check_button.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    
        
        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

        cbtn = Gtk.CheckButton("Show title")
        cbtn.set_active(True)
        cbtn.set_valign(Gtk.Align.START)
        cbtn.connect("clicked", self.on_clicked)

        hbox.pack_start(cbtn, False, False, 0)

        self.add(hbox)

        self.set_border_width(10)
        self.set_title("CheckButton")
        self.set_default_size(300, 180)
        self.connect("destroy", Gtk.main_quit)

    def on_clicked(self, wid):

        if wid.get_active():
            self.set_title("CheckButton")
        else:
           self.set_title("")


win = MyWindow()
win.show_all()
Gtk.main()

The example displays a title in the titlebar of the window depending on the state of the Gtk.CheckButton.

hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)

The button is added to a horizontal box. Gtk.Box is a simple layout manager that arranges widgets in a row or a column.

cbtn = Gtk.CheckButton("Show title")
cbtn.set_active(True)

The Gtk.CheckButton is created. Since by default the title of the window is visible, we activate the button with set_active().

cbtn.connect("clicked", self.on_clicked)

When we check or uncheck the Gtk.CheckButton, the on_clicked() method is called.

def on_clicked(self, wid):

    if wid.get_active():
        self.set_title("CheckButton")
    else:
       self.set_title("")

We determine the state of the Gtk.CheckButton with get_active() and set the title accordingly.

Gtk.CheckButton
Figure: Gtk.CheckButton

Python Gtk.Entry

Gtk.Entry widget is a single line text entry widget. Many key bindings are supported by default. If the entered text is longer than the allocation of the widget, the widget will scroll so that the cursor position is visible.

entry_label.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, Gdk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    

        grid = Gtk.Grid()
        grid.set_column_spacing(5)
        self.add(grid)        

        entry = Gtk.Entry()
        entry.connect("key-release-event", self.on_key_release)

        grid.attach(entry, 0, 0, 1, 1)

        self.label = Gtk.Label("")
        self.label.set_width_chars(15)

        grid.attach(self.label, 1, 0, 1, 1)

        self.set_border_width(5)

        self.set_title("Entry")
        self.set_default_size(300, 180)
        self.connect("destroy", Gtk.main_quit)

    def on_key_release(self, widget, event):
        self.label.set_text(widget.get_text())


win = MyWindow()
win.show_all()
Gtk.main()

In the example, we have an entry widget and a label. The text entered into the entry is displayed in the label.

entry = Gtk.Entry()
entry.connect("key-release-event", self.on_key_release)

We create the Gtk.Entry widget. We connect an event handler to the key-release-event.

def on_key_release(self, widget, event):
    self.label.set_text(widget.get_text())

In the on_key_release() event handler, we get the text from the entry with get_text() and set it to the label with set_text().

Gtk.Entry
Figure: Gtk.Entry

Python Gtk.ComboBoxText

Gtk.ComboBoxText is a simple variant of Gtk.ComboBox that hides the model-view complexity for simple text-only use cases.

combobox_text.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    

        grid = Gtk.Grid()
        grid.set_column_spacing(15)
        self.add(grid)            
        
        combo = Gtk.ComboBoxText()
        grid.attach(combo, 0, 0, 1, 1)

        combo.connect("changed", self.on_changed)

        combo.append_text('Ubuntu')
        combo.append_text('Mandriva')
        combo.append_text('Redhat')
        combo.append_text('Gentoo')
        combo.append_text('Mint')
        
        self.label = Gtk.Label("")
        grid.attach(self.label, 1, 0, 1, 1)

        self.set_border_width(10)
        self.set_title("ComboBoxText")
        self.set_default_size(300, 220)
        self.connect("destroy", Gtk.main_quit)

    def on_changed(self, widget):
        self.label.set_label(widget.get_active_text())         

win = MyWindow()
win.show_all()
Gtk.main()

In the example, we have a Gtk.ComboBoxText and a label. The selected item from the combo box is displayed in the label widget.

combo = Gtk.ComboBoxText()

Gtk.ComboBoxText is created.

combo.connect("changed", self.on_changed)

When the active item is changed, the changed signal is emitted.

combo.append_text('Ubuntu')
combo.append_text('Mandriva')
combo.append_text('Redhat')
combo.append_text('Gentoo')
combo.append_text('Mint')

We add five text items to the combo box.

def on_changed(self, widget):
    self.label.set_label(widget.get_active_text())  

In the on_changed() event handler, we get the active text with get_active_text() and set it to the label with set_label().

Gtk.ComboBoxText
Figure: Gtk.ComboBoxText

Pycairo basic shapes

Pycairo is a Python module providing bindings for the cairo graphics library. Drawing is done on a Gtk.DrawingArea widget. It is essentially a blank widget.

basic_shapes.py
#!/usr/bin/env python3

import gi, math
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk

class MyWindow(Gtk.Window):

    def __init__(self):
        super(MyWindow, self).__init__()

        self.init_ui()

    def init_ui(self):    

        darea = Gtk.DrawingArea()
        darea.connect("draw", self.on_draw)
        self.add(darea)

        self.set_title("Basic shapes")
        self.set_default_size(390, 240)
        
        self.connect("destroy", Gtk.main_quit)

    def on_draw(self, da, ctx):

        ctx.set_source_rgb(0.6, 0.6, 0.6)

        ctx.rectangle(20, 20, 120, 80)
        ctx.rectangle(180, 20, 80, 80)
        ctx.fill()

        ctx.arc(330, 60, 40, 0, 2*math.pi)
        ctx.fill()
        
        ctx.arc(90, 160, 40, math.pi/4, math.pi)
        ctx.fill()

        ctx.translate(220, 180)
        
        ctx.scale(1, 0.7)
        ctx.arc(0, 0, 50, 0, 2*math.pi)
        ctx.fill()        


win = MyWindow()
win.show_all()
Gtk.main()

The example draws a few basic shapes with Pycairo.

darea = Gtk.DrawingArea()
darea.connect("draw", self.on_draw)
self.add(darea)

Drawing is performed on Gtk.DrawingArea. The drawing API is called in the callback of the draw signal.

def on_draw(self, da, ctx):
    ...

The second parameter of on_draw() is the drawing area, the third is the cairo context. The context is an object that is used to draw on all drawable objects.

ctx.set_source_rgb(0.6, 0.6, 0.6)

The set_source_rgb() method sets a colour for the cairo context. The three parameters of the method are the colour intensity values. The values are from 0 to 1.

ctx.rectangle(20, 20, 120, 80)
ctx.rectangle(180, 20, 80, 80)
ctx.fill()

We paint two rectangles. The fill() method paints the interior of the rectangles in the previously set colour.

ctx.arc(330, 60, 40, 0, 2*math.pi)
ctx.fill()

With the arc() method, we paint a full circle.

ctx.translate(220, 180)

The translate() method moves the user-space origin by delta x and delta y.

ctx.scale(1, 0.7)
ctx.arc(0, 0, 50, 0, 2*math.pi)
ctx.fill()   

If we want to draw an oval, we do some scaling first. Here the scale() method shrinks the y axis.

Pycairo basic shapes
Figure: Pycairo basic shapes

Python Gtk.Application

Gtk.Application is a class that handles many important aspects of a GTK+ application such as initialization, application uniqueness, session management, provides some basic scriptability and desktop shell integration. It is recommended to use it together with Gtk.ApplicationWindow.

app.py
#!/usr/bin/env python3

import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gio
import sys


class Window(Gtk.ApplicationWindow):

    def __init__(self, app):
        super(Window, self).__init__(title="Application", application=app)

        grid = Gtk.Grid()

        menubar = Gtk.MenuBar()

        fmi = Gtk.MenuItem.new_with_label("File")

        menu = Gtk.Menu()
        emi = Gtk.MenuItem.new_with_label("Exit") 
        emi.connect("activate", self.quitApp)
        menu.append(emi)
             
        fmi.set_submenu(menu)

        menubar.add(fmi)

        grid.attach(menubar, 0, 0, 1, 1)

        self.add(grid)

        self.set_default_size(280, 180)

    def quitApp(self, par):

        app.quit()
   

class Application(Gtk.Application):

    def __init__(self):
        super(Application, self).__init__()

    def do_activate(self):
    
        self.win = Window(self)
        self.win.show_all()

    def do_startup(self):

        Gtk.Application.do_startup(self)

app = Application()
app.run(sys.argv)

This is a simple example of a Gtk.Application. It contains a menubar.

class Window(Gtk.ApplicationWindow):

    def __init__(self, app):
        super(Window, self).__init__(title="Application", application=app)

Gtk.ApplicationWindow is a Gtk.Window subclass that offers some extra functionality for better integration with Gtk.Application features. Notably, it can handle both the application menu as well as the menubar. It has a parameter reference to the Gtk.Application.

menubar = Gtk.MenuBar()

Gtk.MenuBar creates a classic application menubar. A menubar can contain one or more Gtk.MenuItems.

fmi = Gtk.MenuItem.new_with_label("File")

menu = Gtk.Menu()
emi = Gtk.MenuItem.new_with_label("Exit") 
emi.connect("activate", self.quitApp)
menu.append(emi)
     
fmi.set_submenu(menu)

menubar.add(fmi)

A File menu item is created; it contains a single submenu, which terminates the applicaiton when selected.

class Application(Gtk.Application):

    def __init__(self):
        super(Application, self).__init__()

    def do_activate(self):
    
        self.win = Window(self)
        self.win.show_all()

    def do_startup(self):

        Gtk.Application.do_startup(self)

The do_activate() method is called when the desktop environment launches the application. It is the application entry point. The do_startup() sets up the application when it first starts.

Gtk.Application
Figure: Gtk.Application

In this tutorial, we have created basic GUI applications with Python Gtk.

You might also be interested in the following related tutorials: wxPython tutorial, Tkinter tutorial - procedural style, and PyQt5 tutorial.