Search code examples
pythontkinterraspberry-pistopwatchgpio

Raspberry pi GPIO pins to control Tkinter GUI stopwatch


below are the codes creating Buttons on the GUI to control the stopwatch. I would like to ask if anyone knows how to modified the code in the way such that we can use GPIO pins as input on the raspberry PI (meaning we have 3 push button components to control the stopwatch to function).

What i only know is that we must import RPi.GPIO as GPIO , GPIO.setmode(GPIO.BOARD) and GPIO.setup() the GPIO pins. Anybody can help me???

from Tkinter import *
import time

class StopWatch(Frame):  
    """ Implements a stop watch frame widget. """                                                                
    def __init__(self, parent=None, **kw):        
        Frame.__init__(self, parent, kw)
        self._start = 0.0        
        self._elapsedtime = 0.0
        self._running = 0
        self.timestr = StringVar()               
        self.makeWidgets()      

    def makeWidgets(self):                         
        """ Make the time label. """
        l = Label(self, textvariable=self.timestr)
        self._setTime(self._elapsedtime)
        l.pack(fill=X, expand=NO, pady=2, padx=2)                      

    def _update(self): 
        """ Update the label with elapsed time. """
        self._elapsedtime = time.time() - self._start
        self._setTime(self._elapsedtime)
        self._timer = self.after(50, self._update)

    def _setTime(self, elap):
        """ Set the time string to Minutes:Seconds:Hundreths """
        minutes = int(elap/60)
        seconds = int(elap - minutes*60.0)
        hseconds = int((elap - minutes*60.0 - seconds)*100)                
        self.timestr.set('%02d:%02d:%02d' % (minutes, seconds, hseconds))

    def Start(self):                                                     
        """ Start the stopwatch, ignore if running. """
        if not self._running:            
            self._start = time.time() - self._elapsedtime
            self._update()
            self._running = 1        

    def Stop(self):                                    
        """ Stop the stopwatch, ignore if stopped. """
        if self._running:
            self.after_cancel(self._timer)            
            self._elapsedtime = time.time() - self._start    
            self._setTime(self._elapsedtime)
            self._running = 0

    def Reset(self):                                  
        """ Reset the stopwatch. """
        self._start = time.time()         
        self._elapsedtime = 0.0    
        self._setTime(self._elapsedtime)

def main():

    root = Tk()
    sw = StopWatch(root)
    sw.pack(side=TOP)

    Button(root, text='Start', command=sw.Start).pack(side=LEFT)
    Button(root, text='Stop', command=sw.Stop).pack(side=LEFT)
    Button(root, text='Reset', command=sw.Reset).pack(side=LEFT)
    Button(root, text='Quit', command=root.quit).pack(side=LEFT)

    root.mainloop()

if __name__ == '__main__':
    main()

Solution

  • Makezine propose an extensive tutorial of GPIO use.

    You could poll buttons values in your _update method.

    if self._running and (GPIO.input(23) ==1):
        self.Stop()
    

    This will not work when your clock is not running, so you might adapt your logic to have your _update after-loop to be always running (or create another after-loop dedicated to Pi buttons polling).

    Also, GPIO provide a waitloop in another thread. Here is an adaptation of Makezine's example to link back to tkinter (not tested).

    def relayToTkinter(channel):
        sw.event_generate('<<Start>>', when='tail')
    
    GPIO.add_event_detect(23, GPIO.RISING, callback=relayToTkinter, bouncetime=300)
    sw.bind("<<Start>>", lambda event:sw.Start())
    

    event_generate("<<VirtualEvent>>", when='tail') is a safe way to have another thread interact with main UI thread.