I tired creating a countdown timer. During the duration of the timer the user should be able to enter text. However, it only displays the text after the .after() period (I think thats whats happening at least). It updates after each period and then it displays the text. Is there any workaround for this? Is there any other way to create a countdown timer that would avoid this issue?
import tkinter
from tkinter import *
def showClue(clue):
# Create window
root = tkinter.Tk()
root.state('zoomed')
Grid.rowconfigure(root, 0, weight=1)
Grid.columnconfigure(root, 0, weight=1)
# Frame
clue_frame = tkinter.Frame(root, bg='#0000AF')
clue_frame.pack(expand=True, fill='both')
# Clue label
clue = tkinter.Label(clue_frame, text=clue, bg='#0000AF', fg='white')
clue.config(font=('ITC Korinna Std', 60), wraplength=1250)
# Input
userinput = tkinter.Entry(clue_frame, width=50)
userinput.config(font=('ITC Korinna Std', 25))
# Countdown timer
timer = tkinter.IntVar()
timer.set(15)
time = tkinter.Label(clue_frame,textvariable=timer, bg='#0000AF', fg='white')
time.config(font=('ITC Korinna Std', 50),padx=10,pady=10)
time.pack(anchor='c',expand=True)
clue.pack(anchor= 'c',expand=True)
userinput.pack(anchor='c',expand=True)
timeleft = timer.get()
# Update countdown timer after each second
while timeleft > -1:
root.after(1000)
timer.set(timeleft)
timeleft -= 1
root.update()
root.mainloop()
showClue('test')
What I want this code to do is display the text as the user is typing it and not just after every update.
The root.after method is used to perform some kind of callback as the second parameter for the action it should perform once the time has passed. To fix just create a callback function that updates the variable every second. and continues the countdown inside of the callback.
For example:
import tkinter
from tkinter import *
def countdown(root, timer): # this is the callback function
timeleft = timer.get()
if timeleft > 0:
timer.set(timeleft-1)
root.after(1000, countdown, root, timer) # reschedule callback
def showClue(clue):
# Create window
root = tkinter.Tk()
root.state('zoomed')
Grid.rowconfigure(root, 0, weight=1)
Grid.columnconfigure(root, 0, weight=1)
# Frame
clue_frame = tkinter.Frame(root, bg='#0000AF')
clue_frame.pack(expand=True, fill='both')
# Clue label
clue = tkinter.Label(clue_frame, text=clue, bg='#0000AF', fg='white')
clue.config(font=('ITC Korinna Std', 60), wraplength=1250)
# Input
userinput = tkinter.Entry(clue_frame, width=50)
userinput.config(font=('ITC Korinna Std', 25))
# Countdown timer
timer = tkinter.IntVar()
timer.set(15)
time = tkinter.Label(clue_frame,textvariable=timer, bg='#0000AF', fg='white')
time.config(font=('ITC Korinna Std', 50),padx=10,pady=10)
time.pack(anchor='c',expand=True)
clue.pack(anchor= 'c',expand=True)
userinput.pack(anchor='c',expand=True)
root.after(1000,countdown, root, timer) # start countdown
root.mainloop()
showClue('test')
Related
i want to do a countdown but the changes are not showing until the final one. Example:
def countdown():
# setup of window and other labels etc
timer = calculated time # just placeholder
countdown_time = Message(countdownWindow, text=timer, font=("Courier",16,"bold"), width=100)
time.sleep(1)
while timer != "00:00:00":
timer = calculate time # this time will be a updated current time
root.after(1000, countdown_time.configure(text=timer)
root.after(1000, countdown)
the problem here is that it only opens the window once the final change has been complete, but I want it to update the label every time it is changed
according to your example:
from tkinter import Tk, Button, Label
import time
def countdown():
time_count = 0
time.sleep(1)
while time_count != 10:
time_count += 1
root.after(1000, lbl.configure(text=str(time_count)))
root.update()
root.after(1000, countdown) # invokes an endless loop
root = Tk()
btn = Button(root, text="countdown", command=countdown)
btn.pack()
lbl = Label(root, text="")
lbl.pack()
root.mainloop()
I am trying to create a timer in a tkinter GUI that initiates on a start button, and stops on a stop button. I am using .after to loop the timer, but I can't correctly integrate .after_cancel. Any advice would be greatly appreciated.
#import python modules
import time
import math
from tkinter import *
#Create a root window to work in
root = Tk()
root.title("CNT Synthesis Controller") #title of file
#Create global variables to be stored
global var_status
global current_time
global start_time
current_time = 0
#Create Labels
myLabel_Status_T = Label(root, text="Total time elapsed (hrs:min:sec):")
myLabel_Timer = Label(root, text="00:00:00")
#Locate labels
myLabel_Status_T.grid(row=0, column=0)
myLabel_Timer.grid(row=1, column=0)
#Start button function
def Click_Start():
#disable Start Button to prevent re-start
myButton_Start.config(state=DISABLED)
#initiate time = 0 and start timer
start_time = time.time()
global Timer_continue
Timer_continue = True
#Timer function
def Timer():
#determine the amount of time passed since start_time measured
current_time = int(time.time()-start_time)
hour = math.floor(current_time/3600)
minute = math.floor((current_time/60)-(hour*60))
second = math.floor(current_time-(hour*3600)-(minute*60))
#shows time as 00:00:00, i.e. adding in the zeroes where needed
if hour<10:
hour=str("0"+str(hour))
else:
hour=str(hour)
if minute<10:
minute=str("0"+str(minute))
else:
minute=str(minute)
if second<10:
second=str("0"+str(second))
else:
second=str(second)
#print the time to the label myLabel_Timer
myLabel_Timer.config(text= hour + ":" + minute + ":" + second)
#after 1000 ms repeat the Timer function
#while (myButton_Stop['state'] != tk.DISABLED):
#Timer_Object=myLabel_Timer.after(1000,Timer)
if Timer_continue == True:
root.after(1000,Timer)
if Timer_continue == False:
root.after_cancel(Timer)
Timer()
#Stop button function
def Click_Stop():
Timer_continue = False
#disable Stop Button to prevent re-use until program is reset
myButton_Stop.config(state=DISABLED)
#Create Buttons
myButton_Start = Button(root,text="Start CNT Synthesis", padx=40, pady=20, fg="white", bg="green", command=Click_Start)
myButton_Stop = Button(root,text="Stop CNT Synthesis", padx=40, pady=20, fg="white", bg="red", command=Click_Stop)
#Locate buttons
myButton_Start.grid(row=2, column=0)
myButton_Stop.grid(row=2, column=1)
root.mainloop()
####---------------------------------------------------------------------Required added text to make the question 'long enough'--------------------------------------------------------------------------------------------##########
You need to save the ID returned by .after() and use it in .after_cancel() to stop the timer inside Click_Stop() function:
#import python modules
import time
from tkinter import *
#Create a root window to work in
root = Tk()
root.title("CNT Synthesis Controller") #title of file
#Create Labels
myLabel_Status_T = Label(root, text="Total time elapsed (hrs:min:sec):")
myLabel_Timer = Label(root, text="00:00:00")
#Locate labels
myLabel_Status_T.grid(row=0, column=0)
myLabel_Timer.grid(row=1, column=0)
Timer_id = None # used to store the ID returned by .after()
#Start button function
def Click_Start():
#disable Start Button to prevent re-start
myButton_Start.config(state=DISABLED)
#enable Stop Button
myButton_Stop.config(state=NORMAL)
#save the start timer
start_time = time.time()
#Timer function
def Timer():
global Timer_id
#determine the amount of time passed since start_time measured
elapsed = int(time.time()-start_time)
minutes, seconds = divmod(elapsed, 60)
hours, minutes = divmod(minutes, 60)
myLabel_Timer.config(text=f"{hours:02}:{minutes:02}:{seconds:02}")
#after 1000 ms repeat the Timer function
Timer_id = root.after(1000,Timer) # save the after ID
Timer()
#Stop button function
def Click_Stop():
if Timer_id:
root.after_cancel(Timer_id) # cancel the scheduled task
#disable Stop Button to prevent re-use until program is reset
myButton_Stop.config(state=DISABLED)
#enable Start Button
myButton_Start.config(state=NORMAL)
#Create Buttons
myButton_Start = Button(root,text="Start CNT Synthesis", padx=40, pady=20,
fg="white", bg="green", command=Click_Start)
myButton_Stop = Button(root,text="Stop CNT Synthesis", padx=40, pady=20,
fg="white", bg="red", command=Click_Stop, state=DISABLED) # disable stop button initially
#Locate buttons
myButton_Start.grid(row=2, column=0)
myButton_Stop.grid(row=2, column=1)
root.mainloop()
Miss the global statement:
def Click_Stop():
global Timer_continue
Timer_continue = False
I added the label tag which I thought would solve the problem but when I run the project nothing happens so I kinda at my wit's end also I doing this project is that is important at all to the problem and the ide is Thonny.
#!/usr/bin/python
from tkinter import *
from tkinter import ttk
from tkinter import font
import time
import datetime
global endTime
def quit(*args):
root.destroy()
def show_time():
# Get the time remaining until the event
remainder = endTime - datetime.datetime.now()
# remove the microseconds part
remainder = remainder - datetime.timedelta(microseconds=remainder.microseconds)
# Show the time left
txt.set(remainder)
# Trigger the countdown after 1000ms
root.after(1000, show_time)
# Use tkinter lib for showing the clock
root = Tk()
label(root,text="timer", bg="black", fg=Fdf800")
root.attributes("-fullscreen", True)
root.configure(background='black')
root.bind("x", quit)
root.after(1000, show_time)
# Set the end date and time for the countdown
endTime = datetime.datetime(2017, 9, 19, 9, 0, 0)
fnt = font.Font(family='Helvetica', size=60, weight='bold')
txt = StringVar()
lbl = ttk.Label(root, textvariable=txt, font=fnt, foreground="green", background="black")
lbl.place(relx=0.5, rely=0.5, anchor=CENTER)
root.mainloop()
You need to place a tk.Label() using .pack(), .grid() or .place().
For your use case, it seems .pack() would be suitable; you will want to use this for all your widgets for consistency, e.g.
label = Label(root,text="timer", bg="black")
label.pack()
Full (modified) code:
from tkinter import *
from tkinter import ttk
from tkinter import font
import time
import datetime
def quit(*args):
root.destroy()
def show_time():
# Get the time remaining until the event
remainder = endTime - datetime.datetime.now()
# remove the microseconds part
remainder = remainder - datetime.timedelta(microseconds=remainder.microseconds)
# Show the time left
txt.set(remainder)
# Trigger the countdown after 1000ms
root.after(1000, show_time)
# Use tkinter lib for showing the clock
root = Tk()
label = Label(root,text="timer", bg="black", fg="red")
label.pack()
root.attributes("-fullscreen", True)
root.configure(background='black')
root.bind("x", quit)
root.after(1000, show_time)
# Set the end date and time for the countdown
endTime = datetime.datetime(2017, 9, 19, 9, 0, 0)
fnt = font.Font(family='Helvetica', size=60, weight='bold')
txt = StringVar()
lbl = ttk.Label(root, textvariable=txt, font=fnt, foreground="green", background="black")
lbl.pack()
root.mainloop()
Which produces the result:
I am trying to get the current time to show and update every second in a tkinter label.
Im assuming that i am doing this completely wrong. Im rather new to this and trying to work through it bit by bit.
from tkinter import *
import sys
import time
#function to close window when ESC is pressed
def close(event):
sys.exit()
def curtime():
while 1==1:
current_time = time.strftime('%H:%M:%S')
print(current_time)
time.sleep(1)
#Main System
window = Tk()
window.state('zoomed')
window.configure(bg='#3a3a3a')
#Frames
top_frame = Frame(window)
top_frame.pack(side=TOP)
bottom_frame = Frame(window)
bottom_frame.pack(side=BOTTOM)
#Labels
header_label = Label(top_frame, text="SARA", background='#3a3a3a', fg='#ffffff', font=("calibri", 50))
header_label.pack(side=LEFT)
header_label2 = Label(top_frame, textvariable = curtime(), background='#3a3a3a', fg='#ffffff', font=("calibri", 50))
header_label2.pack(side=LEFT)
#on press ESC window closes
window.bind('<Escape>', close)
window.mainloop()
#function to get timer to calculate
def timer():
timer_tick = strftime("%I:%M:%S")
time_label.configure(text=timer_tick)
time_label.after(1000, timer)
time_label = Label(top_frame, background='#3a3a3a', fg='#ffffff', font=("calibri", 50))
time_label.pack(side=LEFT)
#if statement which constantly returns true to make the timer refresh and tick
if __name__ == "__main__":
timer()
I need a Python script that uses the Tkinter module to create a static (not resizable) window.
I have a pretty simple Tkinter script but I don't want it to be resizable. How do I prevent a Tkinter window from being resizable? I honestly don't know what to do.
This is my script:
from tkinter import *
import ctypes, os
def callback():
active.set(False)
quitButton.destroy()
JustGo = Button(root, text=" Keep Going!", command= lambda: KeepGoing())
JustGo.pack()
JustGo.place(x=150, y=110)
#root.destroy() # Uncomment this to close the window
def sleep():
if not active.get(): return
root.after(1000, sleep)
timeLeft.set(timeLeft.get()-1)
timeOutLabel['text'] = "Time Left: " + str(timeLeft.get()) #Update the label
if timeLeft.get() == 0: #sleep if timeLeft = 0
os.system("Powercfg -H OFF")
os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
def KeepGoing():
active.set(True)
sleep()
quitButton1 = Button(root, text="do not sleep!", command=callback)
quitButton1.pack()
quitButton1.place(x=150, y=110)
root = Tk()
root.geometry("400x268")
root.title("Alert")
root.configure(background='light blue')
timeLeft = IntVar()
timeLeft.set(10) # Time in seconds until shutdown
active = BooleanVar()
active.set(True) # Something to show us that countdown is still going.
label = Label(root, text="ALERT this device will go to sleep soon!", fg="red")
label.config(font=("Courier", 12))
label.configure(background='light blue')
label.pack()
timeOutLabel = Label(root, text = 'Time left: ' + str(timeLeft.get()), background='light blue') # Label to show how much time we have left.
timeOutLabel.pack()
quitButton = Button(root, text="do not sleep!", command=callback)
quitButton.pack()
quitButton.place(x=150, y=110)
root.after(0, sleep)
root.mainloop()
The resizable method on the root window takes two boolean parameters to describe whether the window is resizable in the X and Y direction. To make it completely fixed in size, set both parameters to False:
root.resizable(False, False)