Python Gtk
last modified January 29, 2024
Python Gtk tutorial shows how to create GUI applications in Python using the Gtk module. This tutorial covers GTK 4.
GTK
GTK is a multi-platform toolkit for creating graphical user interfaces. It 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, GTK became one of the most popular toolkits under Linux and BSD Unix.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
print(f'{Gtk.MAJOR_VERSION}.{Gtk.MINOR_VERSION}.{Gtk.MICRO_VERSION}')
We access the GTK library via language introspection. PyGObject is
a language interface to the C library.
import gi
gi.require_version('Gtk', '4.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 libraries.
$ ./version.py 4.6.5
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.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
win.set_title('Simple')
win.present()
app = Gtk.Application(application_id='com.zetcode.Simple')
app.connect('activate', on_activate)
app.run(None)
The example shows a small window on the screen.
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
win.set_title('Simple')
win.present()
We create the main application window inside the on_activate
function. We set the application's title with set_title and present
it to the user with present.
app = Gtk.Application(application_id='com.zetcode.Simple')
app.connect('activate', on_activate)
app.run(None)
We create a new Gtk.Application. To set up the application, we
connect to the activate signal, which is emitted when the
application activation occurs. The run function runs the
application.
In the next example, we rewrite the example in OOP style.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Simple')
self.set_default_size(350, 250)
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.Simple')
app.connect('activate', on_activate)
app.run(None)
We create a class that inherits from Gtk.ApplicationWindow. We
build the UI in the init_ui library.
self.set_default_size(350, 250)
With set_default_size function, we set the default size of the
application window.
Python Gtk.Image
Gtk.Image dispalys an image. If the file is not loaded
successfully, the image will contain a "broken image" icon.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Image')
image = Gtk.Image.new_from_file('sid.png')
self.set_child(image)
self.set_default_size(450, 350)
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.Image')
app.connect('activate', on_activate)
app.run(None)
The example displays a PNG image on the window.
image = Gtk.Image.new_from_file('sid.png')
Gtk.Image is created from a file.
self.set_child(image)
We set the image to the main container of the application window.
Python Gtk.Button
The Gtk.Button is used to trigger a callback function that
is called when the button is pressed.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Quit button')
box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
box.set_margin_start(5)
box.set_margin_top(5)
btn = Gtk.Button(label="Quit")
btn.connect('clicked', lambda _: self.close())
btn.set_halign(Gtk.Align.START)
box.append(btn)
self.set_default_size(350, 250)
self.set_child(box)
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.QuitButton')
app.connect('activate', on_activate)
app.run(None)
In the example, we have a button. When we press the button, the application terminates.
box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0) box.set_margin_start(5) box.set_margin_top(5)
We create a vertical box. We put some margin to the left and top of the box.
Gtk.Box is a simple layout widget that arranges widgets in a row
or a column.
btn = Gtk.Button(label="Quit")
A Gtk.Button is created.
btn.connect('clicked', lambda _: self.close())
When the button is clicked, it emits a clicked signal.
With the connect method we bind the signal to the
self.close method.
btn.set_halign(Gtk.Align.START) box.append(btn)
We align the button to the left of the box and add it to the vertical box.
self.set_default_size(350, 250) self.set_child(box)
Finally, we set the default size of the application window and add the vertical box to the window container.
Python Gtk.CheckButton
Gtk.CheckButton a widget that has two states: on and off. The on
state is visualised by a check mark.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Check button')
box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
box.set_margin_start(5)
box.set_margin_top(5)
cbtn = Gtk.CheckButton.new_with_label('Show title')
cbtn.set_active(True)
cbtn.connect('toggled', self.on_toggle)
box.append(cbtn)
self.set_child(box)
self.set_default_size(450, 350)
def on_toggle(self, wid):
if wid.get_active():
self.set_title('CheckButton')
else:
self.set_title('')
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.CheckButton')
app.connect('activate', on_activate)
app.run(None)
The example displays a title in the titlebar of the window depending on the
state of the Gtk.CheckButton.
cbtn = Gtk.CheckButton.new_with_label('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('toggled', self.on_toggle)
When we check or uncheck the Gtk.CheckButton, the
toggled signal is emitted. We plug the on_toggle
handler to the signal.
def on_toggle(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.
Key pressed event
The next example reacts to a key-pressed event.
#!/usr/bin/python
import gi
from gi.repository import Gtk
gi.require_version("Gtk", "4.0")
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Key press')
keycont = Gtk.EventControllerKey()
keycont.connect('key-pressed', self.on_key_pressed)
self.add_controller(keycont)
self.set_default_size(350, 250)
# keyval, keycode, state, user_data
def on_key_pressed(self, keyval, keycode, *_):
if keycode == ord('q'):
self.close()
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.KeyPress')
app.connect('activate', on_activate)
app.run(None)
The application listens to key-pressed events. If the user enters the q key, the application terminates.
keycont = Gtk.EventControllerKey()
keycont.connect('key-pressed', self.on_key_pressed)
self.add_controller(keycont)
We create and register the Gtk.EventControllerKey. We connect
to the key-pressed signal.
# keyval, keycode, state, user_data
def on_key_pressed(self, keyval, keycode, *_):
if keycode == ord('q'):
self.close()
We check the keycode. If it is q, we close the application.
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.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Quit button')
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8)
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)
vbox.set_margin_start(5)
vbox.set_margin_top(5)
self.entry = Gtk.Entry()
hbox.append(self.entry)
keycont = Gtk.EventControllerKey()
keycont.connect('key-released', self.on_key_released)
self.add_controller(keycont)
self.label = Gtk.Label.new('...')
hbox.append(self.label)
self.set_title('Entry')
self.set_default_size(450, 350)
vbox.append(hbox)
self.set_child(vbox)
def on_key_released(self, *_):
self.label.set_text(self.entry.get_text())
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.QuitButton')
app.connect('activate', on_activate)
app.run(None)
In the example, we have an entry widget and a label. The text entered into the entry is displayed in the label.
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8) hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)
The layout is created with the combination of a vertical and a horizontal box.
self.entry = Gtk.Entry()
We create the Gtk.Entry widget.
keycont = Gtk.EventControllerKey()
keycont.connect('key-released', self.on_key_released)
self.add_controller(keycont)
To be able to process key events, we create a
Gtk.EventControllerKey. We react to the on_key_released
events.
def on_key_released(self, *_):
self.label.set_text(self.entry.get_text())
In the on_key_released event handler, we get the text from the
entry with get_text and set it to the label with
set_text.
Python Gtk.ComboBoxText
Gtk.ComboBoxText is a simple variant of Gtk.ComboBox
that hides the model-view complexity for simple text-only use cases.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Quit button')
vbox = Gtk.Box.new(Gtk.Orientation.VERTICAL, 8)
hbox = Gtk.Box.new(Gtk.Orientation.HORIZONTAL, 8)
combo = Gtk.ComboBoxText()
vbox.set_margin_start(5)
vbox.set_margin_top(5)
hbox.append(combo)
combo.connect('changed', self.on_changed)
combo.append_text('Arch')
combo.append_text('Fedora')
combo.append_text('Redhat')
combo.append_text('Gentoo')
combo.append_text('Xubuntu')
self.label = Gtk.Label.new('')
hbox.append(self.label)
self.set_title('ComboBoxText')
self.set_default_size(450, 350)
vbox.append(hbox)
self.set_child(vbox)
def on_changed(self, wid):
self.label.set_label(wid.get_active_text())
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.ComboBoxText')
app.connect('activate', on_activate)
app.run(None)
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('Arch')
combo.append_text('Fedora')
combo.append_text('Redhat')
combo.append_text('Gentoo')
combo.append_text('Xubuntu')
We add five text items to the combo box.
def on_changed(self, wid):
self.label.set_label(wid.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.
Drawing
Drawing is done on a Gtk.DrawingArea widget.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
import math
from gi.repository import Gtk
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('Drawing')
area = Gtk.DrawingArea.new()
area.set_draw_func(self.on_draw)
self.set_default_size(450, 300)
self.set_child(area)
def on_draw(self, da, ctx, w, h):
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()
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.Drawing')
app.connect('activate', on_activate)
app.run(None)
The example draws a few basic shapes.
area = Gtk.DrawingArea.new() area.set_draw_func(self.on_draw)
We create the Gtk.DrawingArea and set the drawing function with
set_draw_func.
def on_draw(self, da, ctx, w, h):
...
The second parameter of on_draw is the drawing area, the third is
the drawing context. The context is an object that is used to draw on all
drawable objects. The last two parameters are the width and height of the area.
ctx.set_source_rgb(0.6, 0.6, 0.6)
The set_source_rgb method sets a colour for the drawing 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.
Python Gtk.Menu
In the next example, we create an application with a menubar.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui(app)
def init_ui(self, app):
self.set_title('Simple menu')
main = Gio.Menu.new()
fmi = Gio.MenuItem.new('File')
menu = Gio.Menu.new()
emi = Gio.MenuItem.new('Exit', 'app.quit')
menu.append_item(emi)
fmi.set_submenu(menu)
main.append_item(fmi)
app.set_menubar(main)
act_quit = Gio.SimpleAction.new('quit', None)
Gio.ActionMap.add_action(app, act_quit)
act_quit.connect('activate', self.on_close, app)
self.set_show_menubar(True)
self.set_default_size(350, 250)
def on_close(self, *_):
self.close()
def on_activate(app):
win = AppWindow(app)
win.present()
app = Gtk.Application(application_id='com.zetcode.SimpleMenu')
app.connect('activate', on_activate)
app.run(None)
The menubar has a one menu item, which terminates the application.
main = Gio.Menu.new()
fmi = Gio.MenuItem.new('File')
menu = Gio.Menu.new()
emi = Gio.MenuItem.new('Exit', 'app.quit')
menu.append_item(emi)
fmi.set_submenu(menu)
main.append_item(fmi)
We set up the menus and menu items. The app.quit string refers to
an action registered with the application object.
app.set_menubar(main)
We set the menubar with set_menubar.
act_quit = Gio.SimpleAction.new('quit', None)
Gio.ActionMap.add_action(app, act_quit)
act_quit.connect('activate', self.on_close, app)
A simple action is created; the action calls on_close, which
terminates the application.
self.set_show_menubar(True)
We show the menubar with set_show_menubar.
CSS theme
We can theme our applications with CSS.
window {
background-color: rgb(59, 56, 56);
}
button {
color: rgb(233, 32, 27);
}
In the CSS, we set a custom background colour for the window and a custom foreground colour for the button.
#!/usr/bin/python
import gi
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio
class AppWindow(Gtk.ApplicationWindow):
def __init__(self, app):
super(AppWindow, self).__init__(application=app)
self.init_ui()
def init_ui(self):
self.set_title('CSS theme')
box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
btn = Gtk.Button(label="Quit")
btn.connect('clicked', lambda _: self.close())
btn.set_margin_start(5)
btn.set_margin_top(5)
btn.set_halign(Gtk.Align.START)
box.append(btn)
self.set_child(box)
self.set_default_size(350, 250)
def on_activate(app):
win = AppWindow(app)
display = Gtk.Widget.get_display(win)
provider = Gtk.CssProvider.new()
fname = Gio.file_new_for_path('theme.css')
provider.load_from_file(fname)
Gtk.StyleContext.add_provider_for_display(display, provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
win.present()
app = Gtk.Application(application_id='com.zetcode.CheckButton')
app.connect('activate', on_activate)
app.run(None)
Themes are created with Gtk.CssProvider. In this example, we load
the CSS from a file.
display = Gtk.Widget.get_display(win)
provider = Gtk.CssProvider.new()
fname = Gio.file_new_for_path('theme.css')
provider.load_from_file(fname)
Gtk.StyleContext.add_provider_for_display(display, provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
We create a CSS provider, load the theme, and apply the provider to the display.
Source
In this article we have created basic GUI applications with Python Gtk.
Author
List all Python tutorials.