I tried asking this question earlier, but I think this is a better way to ask.
To start:
I am using Windows, and Python 3, with Tkinter
.
I am trying to, on button press, update the first row of my grid, namely page_label
to add a single character over time, and I'm currently attempting this using time.sleep()
inside a for
loop.
This works extremely well when using sys.stdout.write()
without a gui, but I couldn't manage to get anything to write to a label directly, rather than my terminal.
So, I figured I should be able to use the .config
from tkinter
, and just update the label for each character, with a small time delay between each update.
However, when I run the following code, the time delay stacks and the update to the config doesn't run until the end.
So, when I first run the app, I get my initialized text in page_label
.
Then after what I assume is the completion of the for
loop, the final new statement displays as the label updates.
I would be happy with either my current workaround to work, or if there is a nice, clean way to get stdout
to write to the label directly, I'd be extremely pleased.
import time
from tkinter import *
from tkinter.ttk import *
from PIL import Image, ImageFont, ImageTk, ImageDraw
import json
root = Tk()
root.title('actiread test')
root.iconbitmap("C:\\Users\\nicho\\Desktop\\Code Puzzles\\actiread\\actireadico.ico")
root.geometry("800x800")
#button triggering time delay text
def get_input():
words = ""
statement = "I need this to print in time delay"
for char in statement:
words = words char
page_label.config(text = words)
time.sleep(0.2)
#creating updating label
page_label = Label(root, text = "I want to start with an introduction")
#creating button
entry_button = Button(root, text = "Start", command = get_input)
page_label.grid(row = 0, column = 0, columnspan = 2)
entry_button.grid(row = 1, column = 0, pady = 10, sticky = EW)
root.mainloop()
Please ignore the useless imports, I have more to add to the program that I believe will require them.
If it helps, What I'm trying to accomplish will eventually require user inputs that will be saved for later use, and I'll be moving through several versions of this to move through a storyline.
TIA!
CodePudding user response:
The problem is that, when you use time.sleep()
, it blocks the tkinter event loop from processing events and your GUI is stuck since it cannot process events. The right way to do this, is by using root.after(ms, func, *args)
method which will repeat a function after a given amount of time.
def get_input(words="",count=0):
statement = "I need this to print in time delay"
if count < len(statement):
words = statement[count] # Index and get the current letter and add to the current string
page_label.config(text=words)
count = 1
root.after(200,get_input,words,count) # Call the function passing arguments words and count
And another hacky way around this is to use root.update
inside the for loop to force tkinter to process the events, but this is not a good practice.
And a relatively easier solution might be to use global variables instead to understand better:
count = 0
words = ""
def get_input():
global count, words
statement = "I need this to print in time delay"
if count < len(statement):
words = statement[count]
page_label.config(text = words)
count = 1
root.after(200,get_input)
Do note that 200 passed on, is the time for delay in milliseconds, which is same as 0.2 seconds that was passed onto time.sleep