1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/usr/bin/env python

import gtk
import gobject
import Tkinter
import tkMessageBox
import threading
import random

class Window:
    """A GTK window containing progress bars for several horses"""
    horses = []
    finished = False

    def __init__(self,horses):
        """initializes the main window and event bindings"""
        if type(horses) == type([1,]):
            self.horses = horses
        else:
            raise TypeError, 'A List is required. Got ' + str(type(horses)) + ' instead'

        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.vbox = gtk.VBox()
        self.window.add(self.vbox)

        self.vbox.add(gtk.Label('Horse Race'))
        self.table = gtk.Table(len(horses),2)
        self.vbox.add(self.table)

        self.progressbars = []

        for i in range(len(self.horses)):
            self.table.attach(gtk.Label(self.horses[i].name),0,1,i,i+1)
            self.progressbars.append(gtk.ProgressBar())
            self.progressbars[i].set_fraction(0.0)
            self.progressbars[i].set_text('%5.2f%%' % 0.0)
            self.table.attach(self.progressbars[i],1,2,i,i+1)
            

        self.bar = gtk.HBox()
        self.vbox.add(self.bar)

        self.qbutton = gtk.Button(stock=gtk.STOCK_QUIT)
        self.startbutton = gtk.Button(stock=gtk.STOCK_EXECUTE)

        self.bar.add(self.qbutton)
        self.bar.add(self.startbutton)

        self.startbutton.connect('clicked', self.proceed)
        self.qbutton.connect("clicked", self.quit)
        self.window.connect("delete_event", self.quit)
        self.window.connect("destroy", self.quit)
        self.window.show_all()
        
    def main(self):
        """wrapper for gtk.main method"""
        gtk.main()

    def notify(self,horse):
        """Accounces the winner of the race in a Dialog"""
        dialog = gtk.MessageDialog(self.window, 
            gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, 
            gtk.BUTTONS_CLOSE, "And the winner is\n%s" % horse.name)
        dialog.run()
        dialog.destroy()

    def proceed(self,event):
        """starts the race. Uses a Timer from the gobject module"""
        
        # Notice: When writing GTK applications one can use many tools 
        # from the modules gobject and gdk, which provide similar objcts
        # like threading. In some cases gobject just provides more 
        # abstact versions of threading objects...
        for horse in self.horses:
            gobject.timeout_add(
                random.random()*500,
                self.update,
                self.horses.index(horse)
            )

    def quit(self,event):
        """wrapper for gtk.main_quit method; destroys the GTK window"""
        print "Good bye"
        gtk.main_quit()

    def update(self,horse_index):
        """callback function for Timer; updates progress bars"""
        if not Window.finished:
            f = self.horses[horse_index].get_fraction()
            self.progressbars[horse_index].set_fraction(f)
            self.progressbars[horse_index].set_text('%5.2f%%' % (100*f))
            if f == 1.0:
                Window.finished = True
                self.notify(self.horses[horse_index])
                return 0
            else:
                return 1
        else:
            return 0

class TWindow:
    "A Tkinter GUI performing the same task as the GTK version."
    
    horses = []
    finished = False

    def __init__(self,horses):
        """initializes the main window and event bindings"""
        if type(horses) == type([1,]):
            self.horses = horses
        else:
            raise TypeError, 'A List is required. Got ' + str(type(horses)) + ' instead'

        self.window = Tkinter.Tk()
        self.frame = Tkinter.Frame(self.window)
        label=Tkinter.Label(self.window,text='Horse Race')
        label.pack(side="top",fill='x')
        self.frame.pack(side='top',fill='both',expand=True)
        self.progresses = []

        for i in range(len(self.horses)):
            self.progresses.append(Tkinter.Label(self.frame,text= "<--= 00.0% =-->"))
            Tkinter.Label(self.frame,text=self.horses[i].name).grid(row=i+1,column=1)
            self.progresses[i].grid(row=i+1,column=2)
    
        self.startbutton = Tkinter.Button(self.window,text='Start',command=self.proceed)
        self.startbutton.pack(side='left')
        self.quitbutton = Tkinter.Button(self.window,text='Quit',command=self.quit)
        self.quitbutton.pack(side='right')

    def notify(self,i):
        tkMessageBox.showinfo(
            "We have a winner",
            "And the winner is\n<< %s >>" % self.horses[i].name
        )

    def update(self,horse_index):
        """callback function for Timer; updates progress"""
        if not self.finished:
            f = self.horses[horse_index].get_fraction()
            self.progresses[horse_index].configure(text='<--= %04.1F%% =-->' % (100*f))
            if f == 1.0:
                self.finished = True
                self.notify(horse_index)
                
            else:
                self.proceed(horse_index)
            
    def proceed(self,horse_index=None):
        """This method creates a Timer object for each horse waiting between
500ms and 5 seconds before executing the update method"""

        if not horse_index:
            for horse_index in range(len(self.horses)):
                t = threading.Timer(1e-3*random.randint(500,5000),self.update,args=[horse_index,])
                t.start()
        else:
            t = threading.Timer(1e-3*random.randint(500,5000),self.update,args=[horse_index,])
            t.start()
    
    def quit(self):
        self.window.destroy()
    
    def main(self):
        self.window.mainloop()
            
class Horse:
    """Horse that participates in the race."""
    completed = 0.0
    name = 'John Doe'

    def __init__(self,name=None):
        """give the horse at least a name"""
        if name != None:
            self.name = name

    def get_fraction(self):
        """return fraction of progress - and proceed"""
        self.step()
        return self.completed

    def step(self):
        """increases the progress by a random amount"""
        self.completed += .05 * random.random()
        if self.completed > 1:
            self.completed = 1.0

if __name__ == '__main__':
    h = []
    h.append(Horse('John Cleese'))
    h.append(Horse('Peter Falk'))
    h.append(Horse('Peter Sellers'))
    h.append(Horse('Monty Python'))
    w = Window(h)
    w.main()