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()
asked Oct 17, 2018 at 4:57
1
  • 1
    You'll need to use multithreading to do that. I'll write an answer for ya when I'm off mobile Commented Oct 17, 2018 at 21:31

1 Answer 1

1

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.

answered Oct 17, 2018 at 22:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.