1

The following code is a stopwatch on Tkinter which has GPIO involved. I tried adding time.sleep for debouncing the button, but it also delays the stopwatch execution. Makes sense. But I just started using Python and Tkinter, so I don't know how to deal with this for now. Does anyone have a suggestion?

#!/usr/bin/env python3
import tkinter as tk
from threading import Thread
import RPi.GPIO as GPIO
import time
import serial

# GPIO BOARD PIN numbers

# setup GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
ser = serial.Serial ("/dev/ttyS0", 9600)

GPIO.setup(21, GPIO.IN)
GPIO.setup(20, GPIO.IN)
GPIO.setup(16, GPIO.IN)
GPIO.setup(26, GPIO.IN)
GPIO.setup(19, GPIO.IN)
GPIO.setup(13, GPIO.IN)

# Simple status flag
# False mean the timer is not running
# True means the timer is running (counting)
running = False

def update_timeText():
   global running
   global timer
   if running == False and GPIO.input(16) == False:
      running = True
      print('Start')
      ser.write(b'3')
      time.sleep(0.3)  
   elif running == True and GPIO.input(13) == False:
       running = False
       print('Stop')
       ser.write(b'6')
       time.sleep(0.3)      
   elif timer != [0, 0, 0] and running == False and GPIO.input(13) == False:
       timer = [0, 0, 0]
       timeText.configure(text='00:00:00')  
   elif timer != [0, 0, 0] and running == False and GPIO.input(16) == False:
       running = True
       print('Start')
       ser.write(b'3')
       time.sleep(0.3)    
   elif running == True and GPIO.input(20) == False:
        print('Speed up')
        ser.write(b'2')
        time.sleep(0.3)     
   elif running == True and GPIO.input(21) == False:
        print('Speed down')
        ser.write(b'1')
        time.sleep(0.3)
   if running:
# Every time this function is called, we will increment 1 centisecond (1/100 of a second)
        timer[2] += 1
      # Every 100 centisecond is equal to 1 second
        if (timer[2] >= 100):
           timer[2] = 0
           timer[1] += 1
         # Every 60 seconds is equal to 1 min
           if (timer[1] >= 60):
             timer[0] += 1
             timer[1] = 0

# We create our time string here
   timeString = pattern.format(timer[0], timer[1], timer[2])
# Update the timeText Label box with the current time
   timeText.configure(text=timeString)
# Call the update_timeText() function after 1 centisecond
   root.after(10, update_timeText)

# To start the timer
def start():
   global running
   running = True

# To pause the kitchen timer
def pause():
   global running
   running = False

# To reset the timer to 00:00:00
def reset():
   global timer
   timer = [0, 0, 0]
   timeText.configure(text='00:00:00')

# To exit our program
def exit():
    root.destroy()

def exitt(event):
    root.destroy()

root = tk.Tk()

root.attributes("-fullscreen",True)
root.wm_attributes("-topmost",1)
root.bind("<Escape>", exitt)

button_frame = tk.Frame(root)
button_frame.pack(fill=tk.X, side=tk.BOTTOM)

start_button = tk.Button(button_frame, text='Start', command=start, width = 12 , height = 3,bg="green")
stop_button =  tk.Button(button_frame, text='Stop',  command=pause, width = 12 , height = 3,bg="red")
reset_button = tk.Button(button_frame, text='Reset', command=reset, width = 12 , height = 3,bg="yellow")
quit_button =  tk.Button(button_frame, text='Quit',  command=exit, width = 12 , height = 3,bg="grey")

button_frame.columnconfigure(0, weight=1)
button_frame.columnconfigure(1, weight=1)
button_frame.columnconfigure(2, weight=1)
button_frame.columnconfigure(3, weight=1)

start_button.grid(row=0, column=0, sticky=tk.W+tk.E)
stop_button.grid(row=0, column=1, sticky=tk.W+tk.E)
reset_button.grid(row=0, column=2, sticky=tk.W+tk.E)
quit_button.grid(row=0, column=3, sticky=tk.W+tk.E)


# Our time structure [min, sec, centsec]
timer = [0, 0, 0]
# The format is padding all the 
pattern = '{0:02d}:{1:02d}:{2:02d}'

# Create a timeText Label (a text box)
timeText = tk.Label(root, text="00:00:00", font=("Helvetica", 150))
timeText.pack()

update_timeText()
root.mainloop()
  • 1
    You'll need to use multithreading to do that. I'll write an answer for ya when I'm off mobile – Matt Oct 17 '18 at 21:31
0

To 'debounce' a button in tkinter your main script must be continuing to run the root.mainloop loop (as opposed to being stuck in a function call).

To do that you can call button functions in a new thread, allowing the main thread to continue running the main loop.

Here is an example of calling a function in a new thread:

import tkinter as tk
from threading import Thread
from time import sleep

def print_hello():
    print("Hello")
    sleep(3)
    print("Done")

root = tk.Tk()

container = tk.Frame(root)
container.pack(fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)

frame_main = tk.Frame(container)
frame_main.grid(row=0, column=0, sticky="NSEW")

button_hello = tk.Button(frame_main, text="Say Hello", command=lambda: Thread(target=print_hello).start())
button_hello.grid(sticky="NSEW")
root.mainloop()

Notice how you can call the function multiple times before it finishes running.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.