I am looking for a way to implement a time picker in a tkinter application.
I was able to implement this (probably not in the best way) using the spinbox widget and also using @PRMoureu's wonderful answer for validation. What I have right now is this -
import tkinter as tk
class App(tk.Frame):
def __init__(self,parent):
super().__init__(parent)
self.reg=self.register(self.hour_valid)
self.hourstr=tk.StringVar(self,'10')
self.hour = tk.Spinbox(self,from_=0,to=23,wrap=True,validate='focusout',validatecommand=(self.reg,'%P'),invalidcommand=self.hour_invalid,textvariable=self.hourstr,width=2)
self.reg2=self.register(self.min_valid)
self.minstr=tk.StringVar(self,'30')
self.min = tk.Spinbox(self,from_=0,to=59,wrap=True,validate='focusout',validatecommand=(self.reg2,'%P'),invalidcommand=self.min_invalid,textvariable=self.minstr,width=2)
self.hour.grid()
self.min.grid(row=0,column=1)
def hour_invalid(self):
self.hourstr.set('10')
def hour_valid(self,input):
if (input.isdigit() and int(input) in range(24) and len(input) in range(1,3)):
valid = True
else:
valid = False
if not valid:
self.hour.after_idle(lambda: self.hour.config(validate='focusout'))
return valid
def min_invalid(self):
self.minstr.set('30')
def min_valid(self,input):
if (input.isdigit() and int(input) in range(60) and len(input) in range(1,3)):
valid = True
else:
valid = False
if not valid:
self.min.after_idle(lambda: self.min.config(validate='focusout'))
return valid
root = tk.Tk()
App(root).pack()
root.mainloop()
This seems like a pretty common requirement in GUI applications so I think there must be a more standard way to achieve this. How can I implement a user picked time widget in a cleaner way? I am asking this because the tiny feature I want implemented is when incrementing/decrementing the minute-spinbox, if it loops over, the hour-spinbox should accordingly increase/decrease. I thought of achieving this by setting a callback function, but I would not come to know which button of the spinbox exactly was triggered (up or down).