Hi, I’m new here. I’m not a programmer nor will I ever be. I’m an old chess player who has tried to make a gui program to run a Lightning Chess Timer for my local club. It works but not as polished as I’d like and I’ve playing at this on and off for over a year.
‘Lightning Chess’ is nominally 10 seconds per move. It works like this. A buzzer goes off (I use a 3 second foghorn) for 3 seconds and all the White players make their first move during the foghorn; not before and not after. All infringements are an immediate loss as there is no time to argue. For example, you do not announce “check!” If your opponent does not see the check you just take the King and win the game. After the 3 second foghorn there is an adjustable delay. In practice we find 9 seconds delay to be good for most people.
So my gui design is this:
Spinbox to choose the delay seconds, wrapping 2-20.
3 buttons Play, Stop and Quit.
Play and Stop Functions
def play():
global user_input
foghorn = subprocess.call(['mpv', '/$path/foghorn.ogg'])
# Re-schedule this function to run after user_input seconds.
win.after(user_input, play)
def stop():
win.after_cancel(win.after(user_input, play))
The play function works great. No problem, loops on itself.
The stop function cancels the after() timer but the foghorn plays over and over with <1 sec between repeats.
I’ve tried using a global interrupt but with no difference. Any idea what I’m doing wrong please. (BTW the Quit button still works after the short gui freeze.) Ill just post the whole code, might be simpler.
#!/usr/bin/env python3
import tkinter as ttk
from tkinter import Button, Scale, Label
import threading
import subprocess
# global interrupt; interrupt = False
user_input = 9
def on_change():
global user_input
# convert spinbox string to integer then milliseconds
user_input=int(spinbox.get())*1000
def start_timer():
global timer_id
timer_id = win.after(user_input, play)
def play():
global user_input
foghorn = subprocess.call(['mpv', '/home/moss/Python/Lightning/foghorn.ogg'])
# Re-schedule this function to run after user_input seconds.
win.after(user_input, play)
def stop():
win.after_cancel(win.after(user_input, play))
win = ttk.Tk()
win.title("Lightning Chess Timer")
win.geometry("180x140")
spinbox_label = ttk.Label(win, text="2 to 20 seconds pause")
spinbox_label.grid(row=1, column=1, columnspan=2, sticky=ttk.W, padx=5, pady=3)
spinbox = ttk.Spinbox(win, from_=2, to=20, increment=1, font=("Helvetica", 10), wrap=True,
state="readonly", width=5, textvariable=user_input, command=on_change, justify=ttk.RIGHT)
spinbox.grid(row=2, column=1, sticky=ttk.W, padx=5, pady=3)
play_button = ttk.Button(win, text="Play", bg="pale green", command=lambda: [start_timer(), play()])
play_button.grid(row=3, column=1, sticky=ttk.W, padx=5, pady=3)
stop_button = ttk.Button(win, text="Stop", bg="pink", command=stop)
stop_button.grid(row=3, column=2, sticky=ttk.W, padx=5, pady=3)
quit_button = ttk.Button(win, text="Quit", command=win.destroy)
quit_button.grid(row=4, column=1, sticky=ttk.W, padx=5, pady=3)
# 9 is usually good user_value in practice.
win.mainloop()
BTW I run OpenBSD but I’m the least knowledgeable user on the planet and the python version is 3.11