Most of the code for the application is included in a single
main.py file which contains a single
Application class to manage the running of the application and a
main function to start it.
Much of the is very similar to other examples and tutorials. We will focus on the parts that are specific to this example.
Besides standard Python modules such as
Handy module helps us to create adaptive user interfaces. This module is imported in the same way as the
import os import sys import gi gi.require_version('GdkPixbuf', '2.0') gi.require_version('Gtk', '3.0') from gi.repository import GdkPixbuf, GLib, Gtk gi.require_version('Handy', '0.0') from gi.repository import Handy Handy.init() from .widgets import Pages
widgets module contains a helper class that we won’t cover in any detail.
Application class provides the usual methods to set up the application
and perform tasks when it is run.
do_startup method we define two parameters for the thumbnail dimensions:
def do_startup(self): Gtk.Application.do_startup(self) self.thumbnail_width = 160 self.thumbnail_height = 160
These are hard-coded in this example, but more complex applications would load these values from the application’s settings.
do_activate method we set up the user interface, using a helper class to set up an adaptive user interface consisting of two leaflets: one in the window’s header bar, the other in the main area of the window:
def do_activate(self): window = Gtk.ApplicationWindow(application=self) window.set_icon_name('com.example.pictures') title_bar = Handy.TitleBar() window.set_titlebar(title_bar) self.pages = Pages(window, title_bar, 2) self.pages.add_page(self.create_thumbnails_page(), title=_('Pictures')) self.pages.add_page(self.create_details_page()) window.set_default_size(320, 512) window.show_all()
The leaflet in the main area holds two pages: one with a list of thumbnails, the other with a simple image viewer.
For the first page we use a Gtk.ScrolledWindow widget to provide a scrolling list of thumbnails. The thumbnails are held by a Gtk.ListStore object that we create, specifying the data types it holds: a
Pixbuf and a string that holds the file name of the image:
def create_thumbnails_page(self): page = Gtk.ScrolledWindow( halign='center', kinetic_scrolling=True, min_content_width=self.thumbnail_width * 2 ) self.model = Gtk.ListStore(GdkPixbuf.Pixbuf, str) self.load_thumbnails()
We populate the model by calling the
load_thumbnails method which we describe later.
The thumbnails are displayed by a Gtk.IconView widget, using the model as a data source, and mapping the fields in the model to columns in the view.
self.view = Gtk.IconView( activate_on_single_click=True, columns=1, item_width=self.thumbnail_width, model=self.model, selection_mode=Gtk.SelectionMode.BROWSE ) self.view.set_pixbuf_column(0) self.view.set_text_column(1) self.view.connect('item-activated', self.show_details) page.add(self.view) return page
We also connect the
item-activated signal to the
show_details method to respond when the user clicks or touches a thumbnail.
def create_details_page(self): page = Gtk.ScrolledWindow( hexpand=True, kinetic_scrolling=True, vexpand=True ) self.image = Gtk.Image.new_from_icon_name('com.example.pictures', Gtk.IconSize.DIALOG) page.add(self.image) return page
As for the first page, we also return the widget that represents the page.
load_thumbnails method begins by locating the user’s Pictures directory:
def load_thumbnails(self): pictures_dir = GLib.get_user_special_dir( GLib.UserDirectory.DIRECTORY_PICTURES)
As described in the Files section of the Settings, User Data and Files guide, the
GLib.get_user_special_dir function is used to obtain the path to the Pictures directory, specified using the
We iterate over the files in the directory, loading each of them at the size required for the thumbnails, and we add them to the model created in the
for name in os.listdir(pictures_dir): try: pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale( os.path.join(pictures_dir, name), self.thumbnail_width, self.thumbnail_height, True ) if pixbuf: self.model.append([pixbuf, name]) except GLib.Error: pass
Each thumbnail is added as a list of fields with types that correspond to the ones we specified when we created the Gtk.ListStore model.
show_details method loads an image at its full size for display in the details page:
def show_details(self, view, tree_path): pictures_dir = GLib.get_user_special_dir( GLib.UserDirectory.DIRECTORY_PICTURES) tree_iter = self.model.get_iter(tree_path) name = self.model.get_value(tree_iter, 1) try: pixbuf = GdkPixbuf.Pixbuf.new_from_file( os.path.join(pictures_dir, name) ) if pixbuf: self.image.set_from_pixbuf(pixbuf) except GLib.Error: pass # Show the details page and corresponding header. self.pages.show_page(1, name)
We use the Gtk.TreePath passed to this method, along with a Gtk.TreeIter object, to obtain the file name of the image from the model. A good introduction to this class is provided by the Tree and List Widgets chapter of the Python GTK+ 3 Tutorial.
You can access files in specific directories in the user’s home directory by calling the GLib.get_user_special_dir function to obtain the file paths you require. The directory you want to access is specified using a value from the GLib.UserDirectory enum.
In this case we use
DIRECTORY_PICTURES to access the user’s Pictures directory and load images using the GdkPixbuf.Pixbuf class, using the
new_from_file_at_scale method for thumbnails and the
new_from_file method for full size images.
Note that the
load_thumbnails method will only return once all the images have been loaded. If the user has a large number of images in their Pictures directory then the user interface will be unresponsive when the application starts. We could use a background thread or some kind of lazy loading mechanism to make image loading appear quicker.