Posted by T800 on December 9, 2010
The Big Green Clock is a PyGTK example or GTK used in Python. Its a simple 7 segment style real time clock. Here I will walk you through the python elements that makes this clock really tick.

This piece is intended to help someone who has diped there toe in to python and look to play with GTK and the GLADE as method of producing software with a GUI interface. PyGTK is a set of Python wrappers for the GTK+ graphical user interface library.
There are two main methods of using GTK in python. You can create your windows and widgets on the fly. Here is a simple example below will produce a 200x200 pixel window with the words "Hello World" inside.
import gtk
def create_window():
window = gtk.Window()
window.set_default_size(200, 200)
window.connect('destroy', gtk.main_quit)
label = gtk.Label('Hello World')
window.add(label)
label.show()
window.show()
create_window()
gtk.main()You may find The GTK Class Reference useful to follow along with these examples. In the above code window = an instance of GTKwindow, default size 200 x 200. The connect function is connectinng the 'destroy' event which is emitted during the windows closure to the GTKquit call.Then a label instance is generated but this time set to contain the text 'hello world'. The calls show() calls the instances to appear on your screen.
The Big Green Clock uses Glade to create the space holders for the graphical elements that make up the clock. This is prehaps a little over kill for this example, but without I would not be able to show you how to implement glade in your code.
Glade is a RAD tool to enable quick & easy development of user interfaces for the GTK+ toolkit and the GNOME desktop environment.
The user interfaces designed in Glade are saved as XML, and by using the GtkBuilder GTK+ object these can be loaded by applications dynamically as needed.
By using GtkBuilder, Glade XML files can be used in numerous programming languages including C, C++, C#, Vala, Java, Perl, Python,and others.
Glade is Free Software released under the GNU GPL License
The Big Green Code uses the Glade method to setup the clock appearance. There are two files you will need to run this demo, ''bigclock.glade" and "gfx.dat" which contains the compressed digit images. You can find a download link for these files at the bottom of this page. The glade file only contains the table or place holders for the graphics. The windows has 3 rows, the top and bottom for the outer bezel graphics. The centre row has multiple cells across to accommodate the outer bezel graphics and the display digits within.
Using Glade requires a slightly different style of work in python. Firstly lets get some packages imported to support our program...
#!/usr/bin/env python
#
# The BigGreenClock is a time piece for Linux / Win32 systems
# Version 2.6.0 - 09 March 2010 - T800
import sys
import time
import pygtk
import gtk
import gtk.glade
import gobject
import pickle
import gzip
import Image
import cStringIO
import ImageFile
import ImageImporting 'pygtk', 'gtk', 'gtk.glade' and gobject are the key entries for gtk. Next I'm going to create a class for my clock and use to calls to load the glade xml file and build it, then connect a dictonary to my gtk signal to handle events that gtk emits.
class Gui(object):
def __init__(self):
self.gladefile = "bigclock.glade"
self.wTree = gtk.glade.XML(self.gladefile)
dic = { "on_MainWindow_destroy" : self.quit }
self.wTree.signal_autoconnect(dic)So far we have initialised the xml file called "bigclock.glade" for display, but these are only place holders so we need fill the hole with a graphic. The clock uses a crafted data file containing the graphic elements as 'Flat' file. This is a pickle file were the object is an array of jpg files. The reason for vreating the file in this way becomes apparent when we come to display the digits. For now, 22 through to 27 contain the bezel graphics for the suround of the clock. A routine called "blit" fetches the numbered graphic from the file and copies it into our nominated place holder.
self.gfx = self.load('gfx.dat')
self.blit(self.gfx[22], "bottom")
self.blit(self.gfx[23], "left")
self.blit(self.gfx[24], "bright")
self.blit(self.gfx[25], "top")
self.blit(self.gfx[27], "colon")
self.blit(self.gfx[27], "colons")
# Provides our background ticker routine
#
gobject.timeout_add(1000, self.on_timeout)The last line in the last example above adds a gtk timer. After 1000 milliseconds or 1 sec it will call on_timeout() were the display is creatated. The flat file containing the pictures of 7 segment display are arrange in a way to help with the conversion from a decimal number to a displayed digit. The pictures 0 to 9 in the saved file. Thus the value of three corresponds to the picture of a digit tree in seven segment. The large digits used for the hours and minutes simply add ten. So file contents 10 to 19 correspond to the larger digits used.

Using the gtk timer function for keeping time would involve some sort of time set routine to set the current time. Python supplies us with current time access in several forms. The Python time intervals are floating-point numbers in units of seconds. Time() is expressed in seconds since 12:00am, January 1, 1970 or epoch. Using the the function "time.localtime(time.time())" returns a tuple with all the local time information. The indexes 3 to 5 contains all the information we need for the current time to be displayed in our clock.
| Index | Attributes | Values |
|---|---|---|
| 0 | tm_year | 2008 |
| 1 | tm_mon | 1 to 12 |
| 2 | tm_mday | 1 to 31 |
| 3 | tm_hour | 0 to 23 |
| 4 | tm_min | 0 to 59 |
| 5 | tm_sec | 0 to 61 (60 or 61 are leap-seconds) |
| 6 | tm_wday | 0 to 6 (0 is Monday) |
| 7 | tm_yday | 1 to 366 (Julian day) |
| 8 | tm_isdst | -1, 0, 1, -1 means library determines DST |
So in summary with have access to the current time an indexed file containing our graphics for each digit.
def on_timeout(self, *args):
my_clock = time.localtime( time.time() ) # Time is returned as a tuple
hours = int(my_clock[3])
if hours > 12: # Is the hours > 12
hours = hours - 12 # Keep to a 12 hour clock
# # Using the AND function mask off the time there respective units
#
sec = int(my_clock[5])%10
mins = int(my_clock[4])%10
hrs = int(hours)%10
tensec = int(my_clock[5])/10
tenmins = int(my_clock[4])/10
tenhrs = int(hours)/10
# Display the digit in its placeholder
#
self.blit(self.gfx[sec], "sec")
self.blit(self.gfx[tensec], "10sec")
self.blit(self.gfx[mins+10], "min")
self.blit(self.gfx[tenmins+10], "10min")
self.blit(self.gfx[hrs+10], "1hr")
self.blit(self.gfx[tenhrs+20], "10hr")
return True The gtk timer is a one shot time. In other words, use once. It was intended to be used for things like routine timeouts. If you return from this call "True" the timer will restart, if you return "False" it will cancel.
The routine above grabs the current time as a tuple. As we want a 12hr clock it simply subtracts 12 if the hours is greater than 12. The tuple is then broken down in to the into variable for seconds, tens of seconds and so on. Then corresponding picture is loaded into the place holder.
The variable "self.gfx" is a tuple from the pickle file "gfx.dat". If our first seconds digit was the value of five we want to display the 7 segment picture of five. As "self.gfx" is indexed with the graphics 0 - to 9 its just a question of providing a routine to copy the "self.gfx[5]" into the "seconds" image placeholder. This is handled by a routine called "blit"...
# Blit (picture number, GTK image name)
#
def blit(self, picname, seg):
p = ImageFile.Parser()
p.feed(picname)
img = p.close()
pixbuf = self.image_to_pixbuf(img)
image = self.wTree.get_widget(seg)
image.set_from_pixbuf(pixbuf)
def image_to_pixbuf(self, image):
fd = cStringIO.StringIO()
image.save(fd, "ppm")
contents = fd.getvalue()
fd.close()
loader = gtk.gdk.PixbufLoader("pnm")
loader.write(contents, len(contents))
pixbuf = loader.get_pixbuf()
loader.close()
return pixbufBlit is a basic work around of how to get a jpg picture in a tuple into a gtk image. GTK needs a bitmap, a way of converting a variable containing an unknown format is to use the PIL (Python Imaging Libary). PIL has a function called "parser" intended to accept a serial input of data and automatically decode it. So our bitmap image is returned in "img". Now the routine "image_to_pixbuf(img)" is called to use the gtk call "gtk.gdk.PixbufLoader()" to return the pixbuf containing the gtk compatible image. Then the "image.set_from_pixbuf(pixbuf)" call is used to set the gtk image with the pixbuf.
The last routine is the load routine. This is a pickle file saved as a compressed gzip file.
# Loads the gzipped pickle containing the digit graphics
#
def load(self, filename):
file = gzip.GzipFile(filename, 'rb')
buffer = ""
while 1:
data = file.read()
if data == "":
break
buffer += data
object = pickle.loads(buffer)
file.close()
return object I hope you found this article or some of the routines useful. The idea was to introduce you to the glade and class method in python. I will leave you with the complete source listing. And there is a download link at the bottom of this article. Have fun
- #!/usr/bin/env python
- #
- # The BigGreenClock is a time piece for Linux / Win32 systems
- # Version 2.6.0 - 09 March 2010 - T800
-
- import sys
- import time
- import pygtk
- import gtk
- import gtk.glade
- import gobject
- import pickle
- import gzip
- import Image
- import cStringIO
- import ImageFile
- import Image
-
-
-
- class Gui(object):
- def __init__(self):
-
- self.gladefile = "bigclock.glade"
- self.wTree = gtk.glade.XML(self.gladefile)
-
- dic = { "on_MainWindow_destroy" : self.quit }
-
- self.wTree.signal_autoconnect(dic)
-
- # Loads the binary gziped file containing the digit pixmaps
- #
- self.gfx = self.load('gfx.dat')
-
- self.blit(self.gfx[22], "bottom")
- self.blit(self.gfx[23], "left")
- self.blit(self.gfx[24], "bright")
- self.blit(self.gfx[25], "top")
- self.blit(self.gfx[27], "colon")
- self.blit(self.gfx[27], "colons")
-
- # Provides our background ticker routine
- #
- gobject.timeout_add(1000, self.on_timeout)
-
-
- # This is our background timer routine called ever second
- #
- def on_timeout(self, *args):
-
- my_clock = time.localtime( time.time() ) # Time is returned as a tuple
- hours = int(my_clock[3])
- if hours > 12: # Is the hours > 12
- hours = hours - 12 # Keep to a 12 hour clock
-
- # # Using the AND function mask off the time there respective units
- #
- sec = int(my_clock[5])%10
- mins = int(my_clock[4])%10
- hrs = int(hours)%10
- tensec = int(my_clock[5])/10
- tenmins = int(my_clock[4])/10
- tenhrs = int(hours)/10
-
- # Display the digit in its placeholder
- #
- self.blit(self.gfx[sec], "sec")
- self.blit(self.gfx[tensec], "10sec")
- self.blit(self.gfx[mins+10], "min")
- self.blit(self.gfx[tenmins+10], "10min")
- self.blit(self.gfx[hrs+10], "1hr")
- self.blit(self.gfx[tenhrs+20], "10hr")
- return True
-
- # Blit (picture number, GTK image name)
- #
- def blit(self, picname, seg):
- p = ImageFile.Parser()
- p.feed(picname)
- img = p.close()
- pixbuf = self.image_to_pixbuf(img)
- image = self.wTree.get_widget(seg)
- image.set_from_pixbuf(pixbuf)
-
- def image_to_pixbuf(self, image):
- fd = cStringIO.StringIO()
- image.save(fd, "ppm")
- contents = fd.getvalue()
- fd.close()
- loader = gtk.gdk.PixbufLoader("pnm")
- loader.write(contents, len(contents))
- pixbuf = loader.get_pixbuf()
- loader.close()
- return pixbuf
-
- # Loads the gzipped pickle containing the digit graphics
- #
- def load(self, filename):
- file = gzip.GzipFile(filename, 'rb')
- buffer = ""
- while 1:
- data = file.read()
- if data == "":
- break
- buffer += data
- object = pickle.loads(buffer)
- file.close()
- return object
-
- # Bye bye
- #
- def quit(self, widget):
- gtk.main_quit()
-
-
- if __name__ == '__main__':
-
- gobject.threads_init()
- x = Gui()
- gtk.main()
-
| © 2012 Man-Machine. | Powered by concrete5 | Sign In to Edit this Site |