GTK Choice box with Glade and Python

There may be times you have a simple choice or listing in a GTK list box – for this example, in choosing a serial connection or other device. Glade is a good way to build an application window easily with an interface to build in to your app on Linux desktop, Ubuntu or Librem phone or other Linux based phones. I was able to use this to create a Winlink user interface for the previous tutorial to call up the Pat interface.

The first thing we will need is a window, starting out a new file:

Toplevel window selector

Next, add a container into this Gtkwindow – Note the three segments that will be filled in with controls:

GtkBox

Within the GTKBox, add the controls. The right panel will let you change attributes such as the ID (the name you use to reference the control in the code), and various control visibility settings, in the right panel.

GtkBox with GtkButtons

Later when you want to add more buttons or spacers you can select the + button in the right properties box while selecting the GtkBox on the left panel.

Python code running the application and logic

Now we need the code to call up the dialog along with its button functions. When you look up examples to get started, make sure you are looking at GTK3 code and not old “PyGTK” tutorials. This one for example is a good reference for the GTK3 and Python3. The installation instructions should not be necessary on Linux systems on which you can install package “python3-gi”.

To get this working with your code you will need to connect “signals” to methods within a class that controls the window, use builder.connect_signals(class) for the builder instance you use calling up this .glade file when the file is initialized – like so:

import os
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Pango
import json
from pandas import read_json

class Listing:
    def __init__(self):
        pass
        
    def show(self):
        #Create GtkDialog
        self.builder = Gtk.Builder()
        self.builder.add_from_file('Listing.glade')
        self.builder.connect_signals(self)
        self.dialog = self.builder.get_object('MainDialog')
        self.dialog.set_default_size(300,300)
        self.dialog.show_all()
        
    def refresh(self, btn):
        print(btn)
        
    def go(self, btn):
        print('go button clicked')

if __name__ == '__main__':
    dlg = Listing();
    dlg.show()
    Gtk.main()

Now the Listing() class is created, show is called bringing up a dialog, and the “refresh” and “go” are connected to signals selected in the right most panel properties of the button:

You can make a button a “stock” icon button by setting the option in the General panel:

Handling a list

A common control in any application is a list chooser, and the GtkListBox, which can be changed programmatically: Note the clearing removes each child (.get_children()):

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  A Winlink User interface

import os
import sys
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Pango
import json
from pandas import read_json

class Listing:
    def __init__(self):
        pass
        
    def show(self):
        """ Create GtkDialog """
        self.builder = Gtk.Builder()
        self.builder.add_from_file('Listing.glade')
        self.builder.connect_signals(self)
        self.dialog = self.builder.get_object('MainDialog')
        self.dialog.set_default_size(300,300)
        self.refresh(None)
        self.dialog.show_all()
        
    def refresh(self, btn):
        """ Refresh """
        listbox = self.builder.get_object('list')
        for row in listbox.get_children():
            listbox.remove(row)
        if os.path.exists('/dev/serial/by-id'):
            for entry in os.scandir('/dev/serial/by-id'):
                if not entry.name.startswith('.') and not entry.is_dir():
                    path = os.path.normpath(os.path.join(os.path.dirname(entry.path), os.readlink(entry.path)))
                    print(path)
                    self.addEntry(entry.name, path)
        else:
            self.addEntry("No serial devices detected.","")
        listbox.show_all()
        
    def addEntry(self, label, path):
        listbox = self.builder.get_object('list')
        row = Gtk.ListBoxRow()
        hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=0)
        lbl = Gtk.Label(label=label)
        lbl.set_ellipsize(Pango.EllipsizeMode.END)
        hbox.pack_start( lbl, True, True, 2 )
        row.path = path
        row.add(hbox)
        listbox.add(row)
        
    def go(self, btn):
        """ Go button connects, opens browser Pat interface. """
        gtklist = self.builder.get_object('list')
        path = gtklist.get_selected_row().path
        os.system('gksudo kissattach '+path+' wl2k')
        os.system("xdg-open 'http://localhost:8080'")
        os.system('pat http')
        
    def stop(self, btn):
        """ Stop and quit """
        Gtk.main_quit()
        exit;
        
        
        

if __name__ == '__main__':
    dlg = Listing();
    dlg.show()
    Gtk.main()

Review

This lets one call up Pat for a Mobilinkd device with a radio. Check out the full code in the Github Repo!

Leave a Reply

Your email address will not be published.

seventy eight + = eighty eight