24 September 2013

// // Leave a Comment

How to handle command line options in a Python3/Gtk3 application

I have been working for a while on the next generation of Yum Extender.
It is written in Python3 and is using Gtk3 for the gui. The packaging actions is done by two  yum DBus services there is doing all the yum actions. This should make it easier to migrate to DNF or some other packaging backend in the future.

I made a prototype a while ago, but was not satisfied by the look and feel, so I started from scratch again, and started to research on the latest development in Python3/GTK3/PyGObject.

I found some good information resources on these sites


But something like how to handle the command line from at Gtk.Application was hard to find, so I have made a little example Hello world application, show the basics of a Python Gtk3 Application with command line handling.

I

#!/usr/bin/python3 -tt
# -*- coding: utf-8 -*-

#
# Python3 and Gtk3 (via PyGOject) simple demo app by Tim Lauridsen 
#
# It shows the basic elements of a Gtk.Application & Gtk.ApplicationWindow based application in python
# it also shows how to handle command line arguments.
#

# Python import
import sys
import argparse

# python3-gobject import
from gi.repository import Gtk
from gi.repository import Gio
from gi.repository import Gdk

class MyWindow(Gtk.ApplicationWindow):
    """
    Main Application Window
    """
    def __init__(self, app):
        Gtk.Window.__init__(self, title="Gui Test", application=app)
        self.args = app.args # store the args from the application object
        self.set_default_size(400, 400) # set the windows initial size
        self.cnt = 0 # buttom clicked counter

        # create a Grid layout
        self.grid = Gtk.Grid()
        self.grid.set_column_spacing (5)

        # create a button and attact it to the grid
        button = Gtk.Button("Hallo World")
        self.grid.attach(button, 0, 0, 1, 1)
        button.connect("clicked",self.on_button,"custom data")
        # Add a label to the right of the button
        self.label = Gtk.Label("")
        self.label.set_width_chars(50) # set the label width in chars
        self.label.set_alignment(0.02,0.5) # set the (x.y) alignment of the label
        self.grid.attach_next_to(self.label, button, Gtk.PositionType.RIGHT, 1, 1)
        self.grid.show_all() # make all widgets in grid visible
        # add Grid to window
        self.add(self.grid)

    # callback for "button"
    def on_button(self, widget, data):
        self.cnt += 1
        self.label.set_text("Button Clicked : %d" % self.cnt)
        # change label background color, just for the fun of it
        if self.args.color:
            if self.cnt % 2 == 0:
                self.label.override_background_color (Gtk.StateFlags.NORMAL, Gdk.RGBA(255, 0, 0, 1))
            else:
                self.label.override_background_color (Gtk.StateFlags.NORMAL, None)


class MyApplication(Gtk.Application):
    '''
    Main application class
    '''
    def __init__(self):
        # init the parent class
        # the Gio.ApplicationFlags.HANDLES_COMMAND_LINE flags tells that
        # we want to handle the command line and do_command_line will be called
        Gtk.Application.__init__(self,flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE)
        self.args = None # store for parsed command line options

    def do_activate(self):
        '''
        Gtk.Application activate handler
        '''
        # create our main window
        self.win = MyWindow(self)
        # connect a delete_event handler ((riggered by clicking on the windows close button)
        self.win.connect('delete_event', self.on_quit)
        # show the window
        self.win.show()

    def do_startup(self):
        '''
        Gtk.Application startup handler
        '''
        Gtk.Application.do_startup(self)

    def do_command_line(self, args):
        '''
        Gtk.Application command line handler
        called if Gio.ApplicationFlags.HANDLES_COMMAND_LINE is set.
        must call the self.do_activate() to get the application up and running.
        '''
        Gtk.Application.do_command_line(self, args) # call the default commandline handler
        # make a command line parser
        parser = argparse.ArgumentParser(prog='gui')
        # add a -c/--color option
        parser.add_argument('-c', '--color', action='store_true')
        # parse the command line stored in args, but skip the first element (the filename)
        self.args = parser.parse_args(args.get_arguments()[1:])
        # call the main program do_activate() to start up the app
        self.do_activate()
        return 0

    def do_shutdown(self):
        '''
        Gtk.Application shutdown handler
        Do clean up before the application is closed.
        this is triggered when self.quit() is called.
        '''
        Gtk.Application.do_shutdown(self)

    def on_quit(self, widget, data):
        '''
        custom quit handler
        '''
        self.quit() # quit the application


if __name__ == '__main__':
    # make an application object
    app = MyApplication()
    # run the application
    exit_status = app.run(sys.argv)
    # exit with return code
    sys.exit(exit_status)