So i know that in the python window you can use this..
for char in introstring:
sleep(0.2)
sys.stdout.write(char)
sys.stdout.flush()
and it will display the text in the window, character by character at the speed of 0.2
How can I transition this into a Tkinter window? For example, I have the the text:
canvas.create_text((720,454),text="Just in case you start to feel sniffily, or something",fill="white", font=('arial'))
Is there a way to get the same animation but in the Tkinter GUI, I have set up? Ive heard something about the .after command, but I cant seem to find how it would apply for this.
Here's a very simple example that prints text character by character to a canvas, with a delay of 500 milliseconds between characters.
import Tkinter as tk
root = tk.Tk()
canvas = tk.Canvas(root)
canvas.pack()
canvas_text = canvas.create_text(10, 10, text='', anchor=tk.NW)
test_string = "This is a test"
#Time delay between chars, in milliseconds
delta = 500
delay = 0
for i in range(len(test_string) + 1):
s = test_string[:i]
update_text = lambda s=s: canvas.itemconfigure(canvas_text, text=s)
canvas.after(delay, update_text)
delay += delta
root.mainloop()
This code has been tested on Python 2.6. To run it on Python 3 you need to change the import statement to import tkinter as tk
Here's a more sophisticated example that displays text typed into an Entry widget. The text is shown when Enter is pressed in the Entry widget.
#!/usr/bin/env python
''' animate text in a tkinter canvas
See http://stackoverflow.com/q/34973060/4014959
Written by PM 2Ring 2016.01.24
'''
import Tkinter as tk
class Application(object):
def __init__(self):
root = tk.Tk()
self.canvas = tk.Canvas(root)
self.canvas.pack()
self.canvas_text = self.canvas.create_text(10, 10, text='', anchor=tk.NW)
self.entry = tk.Entry(root)
self.entry.bind("<Return>", self.entry_cb)
self.entry.pack()
root.mainloop()
def animate_text(self, text, delta):
''' Animate canvas text with a time delay given in milliseconds '''
delay = 0
for i in range(len(text) + 1):
update_text = lambda s=text[:i]: self.canvas.itemconfigure(self.canvas_text, text=s)
self.canvas.after(delay, update_text)
delay += delta
def entry_cb(self, event):
self.animate_text(self.entry.get(), 250)
app = Application()
Related
i want to animate a label text in tkinter (python). for that purpose, i am using time.sleep() method for updating 1 character in Label widget after a second but it is not updating Label widget instantly rather it is updating label at once at the end of timer. How could i fix this?. Here is my code:-
from tkinter import *
import time
global a
def update(a):
txt = 'Sample Text'
mylabel.configure(text=txt[0:a])
def timer():
global a
a = 0
lenth = len('Sample Text')
start = time.time()
while True:
# Do other stuff, it won't be blocked
time.sleep(0.1)
# When 1 sec or more has elapsed...
if time.time() - start > 1:
start = time.time()
a = a + 1
# This will be updated once per second
print("{} counter".format(a))
update(a)
# Count up to the lenth of text, ending loop
if a > lenth:
break
root = Tk()
root.geometry('300x300')
mylabel = Label(root, text="S", font=('Bell', 36, 'bold'))
mylabel.pack(pady=5)
root.after(3000, timer)
root.mainloop()
It is not recommended to use loop and time.sleep() in the main thread of a tkinter application because it will block the tkinter mainloop() from updating widgets until the loop exits. That is why you can only see the result after the loop completes.
Use .after() instead:
import tkinter as tk
root = tk.Tk()
#root.geometry('300x300')
txt = 'Sample Text'
lbl = tk.Label(root, font='Bell 36 bold', width=len(txt))
lbl.pack(pady=5)
def animate_label(text, n=0):
if n < len(text)-1:
# not complete yet, schedule next run one second later
lbl.after(1000, animate_label, text, n+1)
# update the text of the label
lbl['text'] = text[:n+1]
# start the "after loop" one second later
root.after(1000, animate_label, txt)
root.mainloop()
I am trying to add a progress bar to my window until some work is being done. But it is not working properly. I want it to keep moving until the work is done but it just moves rapidly and then stops. Also if I try to minimize or close the progress window it just hangs and stops responding.
Can anyone help me how can I do it properly? Here is my code.
import time
from tkinter import ttk
from tkinter import *
numbers = []
def main():
main_window = Tk()
app = info(main_window)
main_window.mainloop()
class info:
def __init__(self, root):
# start = timer()
self.error_str = ''
self.root1 = root
self.root1.title('LOADING......')
self.root1.geometry("380x200")
self.root1.eval('tk::PlaceWindow . center')
self.root1.resizable(width=False, height=False)
self.root1.configure(background='white')
progress = ttk.Progressbar(self.root1, orient=HORIZONTAL,
length=380, mode='determinate')
progress.place(x=0, y=100)
i = 20
for x in range(1, 50):
numbers.append(x * 2)
print(numbers)
progress['value'] = i
self.root1.update_idletasks()
time.sleep(0.1)
i = i + 40
self.root = root
self.root.title('Second window')
self.root.geometry('1350x800+0+0')
frame1 = Frame(self.root, bg='#7877a5')
frame1.place(x=0, y=0, width=1350, height=150)
title = Label(frame1, text="Second Window", font=("Times New Roman", 40, "bold", "italic"),
bg='#7877a5',
fg='white')
title.place(x=380, y=45)
if __name__ == '__main__':
main()
Generally speaking you shouldn't call time.sleep() in a tkinter application because it interferes with the GUI's mainloop() and will make your program hang or freeze. Use the universal widget method after() instead.
Lastly you need to specify a maximum value for the Progressbar so its indicator scales properly relatively to the values of i you are setting its value to. The default for maximum is only 100, which your code was greatly exceeding in the for x loop.
Here's the code that needs to change in info.__init__(). The two lines changed have # ALL CAPS comments:
progress = ttk.Progressbar(self.root1, orient=HORIZONTAL,
length=380, mode='determinate',
maximum=(48*40)+20) # ADDED ARGUMENT.
progress.place(x=0, y=100)
i = 20
for x in range(1, 50):
numbers.append(x * 2)
print(numbers)
progress['value'] = i
self.root1.update_idletasks()
self.root1.after(100) # Delay in millisecs. # REPLACED TIME.SLEEP() CALL.
i = i + 40
This question already has answers here:
How do you run your own code alongside Tkinter's event loop?
(5 answers)
Closed 3 years ago.
I want to create a little animation where text appears on an old monochrome terminal like screen as if someone is typing it. However I constantly run into problems with trying to run code after the GUI window opens up. The text is always already there when the window opens or doesnt appear at all. Any help is very appreaciated:)
string = "Hello World this is a Test String"
import random
import time
import tkinter as tk
from tkinter import *
vid = tk.Tk()
vid.title('Terminal')
text = Text( vid, width = 100, height = 50, highlightthickness=1, bg='black', highlightbackground="black", font=('Courier', 14), fg='green')
text.pack()
def main():
for i in string:
text.insert(END, i)
time.sleep(0.2)
text.after(10, main)
vid.mainloop()
This is what I came up with so far:/
You need to use update_idletasks()after your sleep. The following works for me, let me know if you have any other questions:
string = "Hello World this is a Test String"
import random
import time
import tkinter as tk
from tkinter import *
vid = tk.Tk()
vid.title('Terminal')
text = Text( vid, width = 100, height = 50, highlightthickness=1, bg='black', highlightbackground="black", font=('Courier', 14), fg='green')
text.pack()
def main():
for i in string:
text.insert(END, i)
time.sleep(0.2)
vid.update_idletasks()
vid.after(10, main)
vid.mainloop()
It is generally not a good idea to use sleep for an event-driven program (tkinter is event-driven, as it is the case for most GUI libraries). Here, it is better to base your animation on the after method:
import random
import tkinter as tk
string = "Hello World this is a Test String"
def animate(n=0):
text.insert(tk.END, string[n])
n += 1
if n == len(string): # reached end of string
text.insert(tk.END, '\n') # insert newline
n = 0 # and reset current char index
text.after(200, lambda:animate(n)) # call function again in 200ms
vid = tk.Tk()
vid.title('Terminal')
text = tk.Text(vid, width=100, height=50, highlightthickness=1, bg='black',
highlightbackground="black", font=('Courier', 14), fg='green')
text.pack()
vid.after(10, animate)
vid.mainloop()
Note: I've slightly changed your animation to create an infinite loop where the string is endlessly printed char by char, inserting a new line when the end is reached. Just for the fun...
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()
If I created Tkinter window with some text that filled the whole window and now wanted to replace the window with a new text, is there a way to refresh the window?
For Example:
a= 100
win= Tk()
win.geometry("500x300")
while a > 0:
if a%2 == 0:
lbl = Label (win, bg = "purple")
lbl.pack()
else:
lbl = Label (win, bg = "blue")
lbl.pack()
a= x-1
The problem with this code is that the Tkinter window does not refresh and just provides the end result instead of showing the windows changing colors.
Thanks for the help!
That is not the way to change UI states, because even if you refreshed the window it would be so quick you won't notice, instead change the state, wait some time and change the state again e.g. here I show how to animate color
from Tkinter import *
index = 0
def changeColor():
global index
if index%2==0:
label.configure(bg = "purple")
else:
label.configure(bg = "blue")
index+=1
label.after(1000, changeColor)
root = Tk()
mainContainer = Frame(root)
label = Label(mainContainer, text="")
label.configure(text="msg will change every sec")
label.pack(side=LEFT, ipadx=5, ipady=5)
mainContainer.pack()
label.after(1000, changeColor)
root.title("Timed event")
root.mainloop()
This Is How I Do To Update Data From Sql Server in tkinter GUI python3
from tkinter import *
import os
window=Tk()
window.geometry('300x300')
def update():
window.destroy()
os.system('test.py')
Button(window,text="Refresh",command=update)
window.mainloop()