Multithreading in pygtk

My friend Ranganath had some problem with implementing a stopwatch in Java. I told him it would be a piece of cake in python and I would do it in a hour or so . The only thing I do was to call a callback function , whenever I clicked the start button which would set the text in the entry to the time required . This was my code for the call – back function when I clicked on the toggle button.

def start(self , widget):
    if widget.get_active():
        widget.set_label('Stop')
        self.s = time.time()
        while 1:
            time.sleep(0.5)
            self.update()
    else:
        self.entry.set_text(time.time() - self.s)
        widget.set_label('Start')

def update(self):
    self.entry.set_text(time.time() - self.s)

But the program was hanging , and giving me an unresponsive window.

Then my senior-cum-friend Jay asked me to look at multithreading in gtk , for modifying text , label or entry  in a gtk window . So I read a bit of multi – threading in python . This is an example of a simple thread in python.

import threading , time
def foo_fun(name , sleeptime):
    print 'Thread %s is running' % (str(i))
    time.sleep(sleeptime)

if __name__ == '__main__':
    for i in range(5):
        threading.Thread(target = foo_fun , args = (i , 1)

A major feature of multithreading is that it once a string is set up , it does not wait for that to end, the other string is simulaneously set up and run. This increases speed and can sometimes lead to varied output. My understanding of this is based on the answers given in the question asked on stack.

http://stackoverflow.com/questions/11899224/multithreading-in-python

Now coming back to the stopwatch question , two major things should be done according to the blog – link Jay gave me , first one is  that gtk Threads are initialized in this way gtk.gdk.threads_init()  , and whenever something is modified in the window , gobject.idle_add() should be called.

This is my code for the stopwatch program. First the main window

self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
self.window.set_title('Stopwatch')
self.window.set_size_request(200,200)
self.table = gtk.Table(10,20,True)
self.entry = gtk.Entry()
self.entry.set_editable(False)
self.table.attach(self.entry , 0 , 20 , 2 , 4)
self.button = gtk.ToggleButton(label = 'Start')
self.button.connect('toggled' , self.count)
self.table.attach(self.button , 6 , 14 ,  6 ,10)
self.image = gtk.Image()
self.image.set_from_file('stop.jpg')
self.table.attach(self.image , 0 ,20, 0 ,10)
self.window.add(self.table)
self.window.connect('delete-event' , gtk.main_quit)
self.window.show_all()

Nothing new about this except the fact that Ive used a toggle button , and used an image that I downloaded from
Google as background.

Rest of my code

def count(self,widget):
    if widget.get_active():
        self.s = time.time()
        threading.Thread(target = self.ent_change).start()
        widget.set_label('Stop')
    else:
        widget.set_label('Start')

def ent_change(self):

while 1:
    time.sleep(0.01)
    gobject.idle_add(self.change)

    if self.button.get_active() == 0:
        break

def change(self):
    show = time.time() - self.s
    hour = show / 3600
    minutes = (show % 3600) / 60
    seconds = show - (int(hour) * 3600) - (int(minutes) * 60)
    string = ' %s : %s : %0.2f ' % (str(int(hour)),str(int(minutes)),seconds)
    self.entry.set_text(string)

Looking at each function one by one

1.count
Once the toggle button is toggled with , it calls the function count. If the widget is already on , at the time
of toggling , it changes the label to Stop and records time.time() in a variable that can be accessed throughout
and it starts a thread which calls the function ent_change. If the widget is off , it just changes the button l
abel to ‘Stop’

2. ent_change
This runs an infinite loop which calls upon the function change using gobject.idle_add() every 0.01 seconds. Ev
erytime it checks if the button is active or not. If it isnt it terminates the loop , while breaking the thread.

3.change
It just updates the text in the entry box every 0.01 seconds

This is a screenshot showing my running stopwatch.


Thanks for reading.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: