Update time for recording - python

I doing a simple python GUI using tkinter to do screen recording.Basically, I am using ffmpeg commands at the backend with tkinter as the front end triggering the ffmpeg commands.There is something that I stuck with.I dont know why my time is unable to trigger off if I program in this way.
The code below is basically the recording method.You will notice that I am actually trying to update my tkinter GUI in the while loop.This method is actually in my class named Gui_Rec() which contains other methods I need for my screen recording program.
def rec(self):
global videoFile
mydate = datetime.datetime.now()
videoFile = mydate.strftime("\%d%b_%Hh%Mm.avi")
self.l['text']=os.path.expanduser('~')+"\Videos"
self.l1['text']=videoFile
self.b.config(state=DISABLED)
self.b1.config(state=ACTIVE)
t = Thread(target=self.rec_thread)#trigger another method using thread which will run ffmpeg commands here
t.start()
while True:
if self.count_flag == False:
break
self.label['text'] = str("%02dm:%02ds" % (self.mins,self.secs))
if self.secs == 0:
time.sleep(0)
else:
time.sleep(1)
if(self.mins==0 and self.secs==1):
self.b1.config(fg="white")
self.b1.config(bg="red")
self.b.config(fg="white")
self.b.config(bg="white")
if self.secs==60:
self.secs=0
self.mins+=1
self.label['text'] = str("%02dm:%02ds" % (self.mins,self.secs))
main.gui.update()
self.secs = self.secs+1
other method in the class Gui_Rec() then this below
def main():
gui = Gui_Rec()
gui.minsize(300,155)
gui.maxsize(390,195)
gui.title("Desktop REC")
gui.attributes("-topmost", 1)
gui.mainloop() #start mainloop of program
if __name__ == '__main__':
main()
Strangely, if I don't put the above section of code in the the def main(), the GUI will be update with the duration of the time running when rec button is pressed.I don't really know how to go about solving this.Tried putting it in another thread yet it doesn't work as well.Thank you everyone for your help.

The while loop is creating a conflict with Tkinter's mainloop. Threading or multiprocessing are solutions, but I'd recommend looking into Tkinter's after() method. Here's a simplified example of how to handle a timer using after:
from Tkinter import *
class App(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.mins = 0
self.secs = 0
# make a stringvar instance to hold the time
self.timer = StringVar()
self.timer.set('%d:%d' % (self.mins, self.secs))
Label(self, textvariable=self.timer).pack()
Button(self, text='Start', command=self._start_timer).pack()
Button(self, text='Stop', command=self._stop_timer).pack()
def _start_timer(self):
self.secs += 1 # increment seconds
if self.secs == 60: # at every minute,
self.secs = 0 # reset seconds
self.mins += 1 # and increment minutes
self.timer.set('%d:%d' % (self.mins, self.secs))
# set up the after method to repeat this method
# every 1000 ms (1 second)
self.repeater = self.after(1000, self._start_timer)
def _stop_timer(self):
self.after_cancel(self.repeater)
root = Tk()
App(root).pack()
mainloop()

Related

Pause button does not work, how do I use after_cancel properly?

So I am making a program that has a timer and the timer works, now I am working with a pause function. After some research, I found a function called after_cancel. This function supposedly should cancel the after function as the after function in this situation creates an infinite loop. How do I use the after_cancel properly in this situation or are there any other possible solutions?
Thanks in advance.
t = 60000
global timerState
timerState = True
def pause():
timerLabel.after_cancel(countdown)
timerState = False
timerButton.config(text="Play", command=countdown)
def countdown():
global t
if t == 0:
timer = "00:00"
timerLabel.config(text=timer)
return
if timerState == False:
timerLabel.after_cancel(countdown)
timerButton.config(text="Play", command=countdown)
return
mins = t / 60000
secs = t / 1000
secs = secs - int(mins) * 60
mills = t
mills = mills - int(secs) * 1000
if timerState == True:
timer = "{:02d}:{:02d}".format(int(mins),int(secs))
timerLabel.config(text=timer)
t -= 1
timerLabel.after(1, countdown)
timerButton.config(text="Pause", command=pause)
Most of the time .after_cancel scripts can be avoided by just using if statements. For example look at this:
import tkinter as tk
t = 60000
def pause():
global timerState
timerState = False
timerButton.config(text="Play", command=start_countdown)
def start_countdown():
global timerState
timerState = True
timerButton.config(text="Pause", command=pause)
countdown()
def countdown():
global t
if timerState:
timerLabel.config(text=t)
t -= 1
if t > 0:
timerLabel.after(1, countdown)
root = tk.Tk()
timerLabel = tk.Label(root, text="")
timerLabel.pack()
timerButton = tk.Button(root, text="Play", command=start_countdown)
timerButton.pack()
root.mainloop()
I modified your code to show t without making it in the mm:ss format. The main point is that if timerState is False the timerLabel.after(1, countdown) will never be called so there is no point to having a .after_cancel.
Note: You haven't considered the time taken for your other code so t isn't really in milliseconds (at least for my slow computer).
Here is a demonstration of after and after_cancel
Every after needs to be cancelled in order to clear the event queue.
In this program, each time the button is pressed a time delay event is generated.
The event ID is stored in self.after_time
I have set the delay value to increase by 100 ms with each button press, for demo purposes.
it withdraws the master from view.
When the time delay event is complete it calls self.action
self.action cancels the event with after_cancel( self.after_time )
and the master is made visible, ready for the next button press.
import tkinter
class after_demo:
delay = 100
def __init__( self ):
self.master = tkinter.Tk()
self.master.title( 'After Demo' )
self.control = tkinter.Button(
self.master, text = 'Begin Demo',
width = 40, command = self.pause )
self.control.grid(row=0,column=0,sticky='nsew')
def action( self ):
self.master.after_cancel( self.after_time )
self.control[ 'text' ] = 'Delay( {} ) ms'.format( self.delay )
self.master.deiconify()
def pause( self ):
self.after_time = self.master.after( self.delay, self.action )
self.delay += 100
self.master.withdraw()
if __name__ == '__main__':
timer = after_demo( )
tkinter.mainloop()

How to create a timer with tkinter? I am learning Python [duplicate]

I'm writing a program with Python's tkinter library.
My major problem is that I don't know how to create a timer or a clock like hh:mm:ss.
I need it to update itself (that's what I don't know how to do); when I use time.sleep() in a loop the whole GUI freezes.
Tkinter root windows have a method called after which can be used to schedule a function to be called after a given period of time. If that function itself calls after you've set up an automatically recurring event.
Here is a working example:
# for python 3.x use 'tkinter' rather than 'Tkinter'
import Tkinter as tk
import time
class App():
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(text="")
self.label.pack()
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime("%H:%M:%S")
self.label.configure(text=now)
self.root.after(1000, self.update_clock)
app=App()
Bear in mind that after doesn't guarantee the function will run exactly on time. It only schedules the job to be run after a given amount of time. It the app is busy there may be a delay before it is called since Tkinter is single-threaded. The delay is typically measured in microseconds.
Python3 clock example using the frame.after() rather than the top level application. Also shows updating the label with a StringVar()
#!/usr/bin/env python3
# Display UTC.
# started with https://docs.python.org/3.4/library/tkinter.html#module-tkinter
import tkinter as tk
import time
def current_iso8601():
"""Get current date and time in ISO8601"""
# https://en.wikipedia.org/wiki/ISO_8601
# https://xkcd.com/1179/
return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.now = tk.StringVar()
self.time = tk.Label(self, font=('Helvetica', 24))
self.time.pack(side="top")
self.time["textvariable"] = self.now
self.QUIT = tk.Button(self, text="QUIT", fg="red",
command=root.destroy)
self.QUIT.pack(side="bottom")
# initial time display
self.onUpdate()
def onUpdate(self):
# update displayed time
self.now.set(current_iso8601())
# schedule timer to call myself after 1 second
self.after(1000, self.onUpdate)
root = tk.Tk()
app = Application(master=root)
root.mainloop()
from tkinter import *
import time
tk=Tk()
def clock():
t=time.strftime('%I:%M:%S',time.localtime())
if t!='':
label1.config(text=t,font='times 25')
tk.after(100,clock)
label1=Label(tk,justify='center')
label1.pack()
clock()
tk.mainloop()
You should call .after_idle(callback) before the mainloop and .after(ms, callback) at the end of the callback function.
Example:
import tkinter as tk
import time
def refresh_clock():
clock_label.config(
text=time.strftime("%H:%M:%S", time.localtime())
)
root.after(1000, refresh_clock) # <--
root = tk.Tk()
clock_label = tk.Label(root, font="Times 25", justify="center")
clock_label.pack()
root.after_idle(refresh_clock) # <--
root.mainloop()
I have a simple answer to this problem. I created a thread to update the time. In the thread i run a while loop which gets the time and update it. Check the below code and do not forget to mark it as right answer.
from tkinter import *
from tkinter import *
import _thread
import time
def update():
while True:
t=time.strftime('%I:%M:%S',time.localtime())
time_label['text'] = t
win = Tk()
win.geometry('200x200')
time_label = Label(win, text='0:0:0', font=('',15))
time_label.pack()
_thread.start_new_thread(update,())
win.mainloop()
I just created a simple timer using the MVP pattern (however it may be
overkill for that simple project). It has quit, start/pause and a stop button. Time is displayed in HH:MM:SS format. Time counting is implemented using a thread that is running several times a second and the difference between the time the timer has started and the current time.
Source code on github
from tkinter import *
from tkinter import messagebox
root = Tk()
root.geometry("400x400")
root.resizable(0, 0)
root.title("Timer")
seconds = 21
def timer():
global seconds
if seconds > 0:
seconds = seconds - 1
mins = seconds // 60
m = str(mins)
if mins < 10:
m = '0' + str(mins)
se = seconds - (mins * 60)
s = str(se)
if se < 10:
s = '0' + str(se)
time.set(m + ':' + s)
timer_display.config(textvariable=time)
# call this function again in 1,000 milliseconds
root.after(1000, timer)
elif seconds == 0:
messagebox.showinfo('Message', 'Time is completed')
root.quit()
frames = Frame(root, width=500, height=500)
frames.pack()
time = StringVar()
timer_display = Label(root, font=('Trebuchet MS', 30, 'bold'))
timer_display.place(x=145, y=100)
timer() # start the timer
root.mainloop()
You can emulate time.sleep with tksleep and call the function after a given amount of time. This may adds readability to your code, but has its limitations:
def tick():
while True:
clock.configure(text=time.strftime("%H:%M:%S"))
tksleep(0.25) #sleep for 0.25 seconds
root = tk.Tk()
clock = tk.Label(root,text='5')
clock.pack(fill=tk.BOTH,expand=True)
tick()
root.mainloop()

How do I properly update the countdown timer in one second intervals in the main window? [duplicate]

I'm writing a program with Python's tkinter library.
My major problem is that I don't know how to create a timer or a clock like hh:mm:ss.
I need it to update itself (that's what I don't know how to do); when I use time.sleep() in a loop the whole GUI freezes.
Tkinter root windows have a method called after which can be used to schedule a function to be called after a given period of time. If that function itself calls after you've set up an automatically recurring event.
Here is a working example:
# for python 3.x use 'tkinter' rather than 'Tkinter'
import Tkinter as tk
import time
class App():
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(text="")
self.label.pack()
self.update_clock()
self.root.mainloop()
def update_clock(self):
now = time.strftime("%H:%M:%S")
self.label.configure(text=now)
self.root.after(1000, self.update_clock)
app=App()
Bear in mind that after doesn't guarantee the function will run exactly on time. It only schedules the job to be run after a given amount of time. It the app is busy there may be a delay before it is called since Tkinter is single-threaded. The delay is typically measured in microseconds.
Python3 clock example using the frame.after() rather than the top level application. Also shows updating the label with a StringVar()
#!/usr/bin/env python3
# Display UTC.
# started with https://docs.python.org/3.4/library/tkinter.html#module-tkinter
import tkinter as tk
import time
def current_iso8601():
"""Get current date and time in ISO8601"""
# https://en.wikipedia.org/wiki/ISO_8601
# https://xkcd.com/1179/
return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
self.pack()
self.createWidgets()
def createWidgets(self):
self.now = tk.StringVar()
self.time = tk.Label(self, font=('Helvetica', 24))
self.time.pack(side="top")
self.time["textvariable"] = self.now
self.QUIT = tk.Button(self, text="QUIT", fg="red",
command=root.destroy)
self.QUIT.pack(side="bottom")
# initial time display
self.onUpdate()
def onUpdate(self):
# update displayed time
self.now.set(current_iso8601())
# schedule timer to call myself after 1 second
self.after(1000, self.onUpdate)
root = tk.Tk()
app = Application(master=root)
root.mainloop()
from tkinter import *
import time
tk=Tk()
def clock():
t=time.strftime('%I:%M:%S',time.localtime())
if t!='':
label1.config(text=t,font='times 25')
tk.after(100,clock)
label1=Label(tk,justify='center')
label1.pack()
clock()
tk.mainloop()
You should call .after_idle(callback) before the mainloop and .after(ms, callback) at the end of the callback function.
Example:
import tkinter as tk
import time
def refresh_clock():
clock_label.config(
text=time.strftime("%H:%M:%S", time.localtime())
)
root.after(1000, refresh_clock) # <--
root = tk.Tk()
clock_label = tk.Label(root, font="Times 25", justify="center")
clock_label.pack()
root.after_idle(refresh_clock) # <--
root.mainloop()
I have a simple answer to this problem. I created a thread to update the time. In the thread i run a while loop which gets the time and update it. Check the below code and do not forget to mark it as right answer.
from tkinter import *
from tkinter import *
import _thread
import time
def update():
while True:
t=time.strftime('%I:%M:%S',time.localtime())
time_label['text'] = t
win = Tk()
win.geometry('200x200')
time_label = Label(win, text='0:0:0', font=('',15))
time_label.pack()
_thread.start_new_thread(update,())
win.mainloop()
I just created a simple timer using the MVP pattern (however it may be
overkill for that simple project). It has quit, start/pause and a stop button. Time is displayed in HH:MM:SS format. Time counting is implemented using a thread that is running several times a second and the difference between the time the timer has started and the current time.
Source code on github
from tkinter import *
from tkinter import messagebox
root = Tk()
root.geometry("400x400")
root.resizable(0, 0)
root.title("Timer")
seconds = 21
def timer():
global seconds
if seconds > 0:
seconds = seconds - 1
mins = seconds // 60
m = str(mins)
if mins < 10:
m = '0' + str(mins)
se = seconds - (mins * 60)
s = str(se)
if se < 10:
s = '0' + str(se)
time.set(m + ':' + s)
timer_display.config(textvariable=time)
# call this function again in 1,000 milliseconds
root.after(1000, timer)
elif seconds == 0:
messagebox.showinfo('Message', 'Time is completed')
root.quit()
frames = Frame(root, width=500, height=500)
frames.pack()
time = StringVar()
timer_display = Label(root, font=('Trebuchet MS', 30, 'bold'))
timer_display.place(x=145, y=100)
timer() # start the timer
root.mainloop()
You can emulate time.sleep with tksleep and call the function after a given amount of time. This may adds readability to your code, but has its limitations:
def tick():
while True:
clock.configure(text=time.strftime("%H:%M:%S"))
tksleep(0.25) #sleep for 0.25 seconds
root = tk.Tk()
clock = tk.Label(root,text='5')
clock.pack(fill=tk.BOTH,expand=True)
tick()
root.mainloop()

Python Set Button Text While busy

I'm new to python and I am trying to create a program but I can't even get the basics right. I have a button app that looks like this:
#simple GUI
from tkinter import *
import time
#create the window
root = Tk()
#modify root window
root.title("Button Example")
root.geometry("200x50")
button1state = 0
def start():
count = 0
button1["text"] ="Busy!"
while (count < 5):
root.after(1000)
count = count + 1
def button1clicked():
global button1state
if button1state == 0:
start()
button1["text"] ="On!"
button1state = 1
else:
button1["text"] ="Off!"
button1state = 0
app = Frame(root)
app.pack()
button1 = Button(app, text ="Off!", command = button1clicked)
button1.pack()
#kick off the event loop
root.mainloop()
Now everything works except it doesn't change the button text to busy while
**start()** is called. How can I fix this? Once I've got it working I want to use images to show the user that its OFF ON and BUSY. Please help me
You need to force the GUI to update before starting the task:
def start():
count = 0
button1.configure(text="Busy!")
root.update() # <-- update window
while (count < 5):
root.after(1000)
count = count + 1
But if you don't want your GUI to be frozen while the task is executed, you will need to use a thread as Dedi suggested.
You have to make a thread in order to make you function as a "background event" while your interface is working. Consider using that :
from threading import Thread
and then :
my_thread=Thread(target=start())
my_thread.start()
Where the first "start()" is the name of your function and the second one a call for the thread to begin.

Making a countdown timer with Python and Tkinter?

I want to set a label in Tkinter using my countdown timer function. Right now all it does is set the lable to "10" once 10 is reached and I don't really understand why. Also, even if I have the timer print to a terminal instead the "Time's up!" bit never prints.
import time
import tkinter as tk
class App():
def __init__(self):
self.root = tk.Tk()
self.label = tk.Label(text="null")
self.label.pack()
self.countdown()
self.root.mainloop()
# Define a timer.
def countdown(self):
p = 10.00
t = time.time()
n = 0
# Loop while the number of seconds is less than the integer defined in "p"
while n - t < p:
n = time.time()
if n == t + p:
self.label.configure(text="Time's up!")
else:
self.label.configure(text=round(n - t))
app=App()
Tkinter already has an infinite loop running (the event loop), and a way to schedule things to run after a period of time has elapsed (using after). You can take advantage of this by writing a function that calls itself once a second to update the display. You can use a class variable to keep track of the remaining time.
import Tkinter as tk
class ExampleApp(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.label = tk.Label(self, text="", width=10)
self.label.pack()
self.remaining = 0
self.countdown(10)
def countdown(self, remaining = None):
if remaining is not None:
self.remaining = remaining
if self.remaining <= 0:
self.label.configure(text="time's up!")
else:
self.label.configure(text="%d" % self.remaining)
self.remaining = self.remaining - 1
self.after(1000, self.countdown)
if __name__ == "__main__":
app = ExampleApp()
app.mainloop()

Categories

Resources