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.
GTKGTK 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.
version.py
#!/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.5Python 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/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.
simple2.py
#!/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.
Gtk.Image
dispalys an image. If the file is not loaded successfully, the image will contain a "broken image" icon.
image.py
#!/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.ButtonThe Gtk.Button
is used to trigger a callback function that is called when the button is pressed.
quit_button.py
#!/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.
Figure: Quit button Python Gtk.CheckButtonGtk.CheckButton
a widget that has two states: on and off. The on state is visualised by a check mark.
check_button.py
#!/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.
The next example reacts to a key-pressed
event.
key_pressed.py
#!/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.EntryGtk.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/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
.
Gtk.ComboBoxText
is a simple variant of Gtk.ComboBox
that hides the model-view complexity for simple text-only use cases.
combo.py
#!/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 is done on a Gtk.DrawingArea
widget.
shapes.py
#!/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.
In the next example, we create an application with a menubar.
menu.py
#!/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
.
We can theme our applications with CSS.
theme.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.
css_theme.py
#!/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.
Figure: CSS theme SourceIn this article we have created basic GUI applications with Python Gtk.
My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.
List all Python tutorials.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4