Dave Mathews
Dave Mathews

Reputation: 177

Python Tkinter How to update a text widget in a for loop?

I am trying to update text in a scrolltext widget within a for loop. The print statement shows the updated text each time through the loop but the I don't see anything in the Tk window until the loop has completed. Then I see '('This is ', 4, ' times though the loop.')'. I never see 0 through 3 being displayed.

from   tkinter import *
from   tkinter import scrolledtext
import time

main = Tk()
main.title("test_loop")
main.geometry('750x625')
main.configure(background='ivory3')


def show_msg():
    global texw
    textw = scrolledtext.ScrolledText(main,width=40,height=25)
    textw.grid(column=0, row=1,sticky=N+S+E+W)
    textw.config(background="light grey", foreground="black",
             font='arial 20 bold', wrap='word', relief="sunken", bd=5)
    for i in range(5):
        txt = "This is ", i, " times though the loop."
        txt = str(txt)
        print(txt)
        textw.delete('1.0', END)  # Delete any old text on the screen
        textw.update()            # Clear the screen.
        textw.insert(END, txt)    # Write the new data to the screen
        time.sleep(5)

btn = Button(main, text = 'display_log', bg='light grey', width = 15, 
         font='arial 12', relief="raised",bd=5,command = show_msg)
btn = btn.grid(row = 0, column = 0)

main.mainloop()

Upvotes: 0

Views: 5683

Answers (3)

rizerphe
rizerphe

Reputation: 1390

The problem is that your window is not getting updated until the loop is running. To avoid it 'freezing', you should update it periodically. Do something like this:

from tkinter import *
do_your_init()
tk = Tk()
do_your_preparation()
for x in range(n):
    do_your_update()
    tk.update()

Hope that's helpful! Good luck!

Upvotes: 5

Mike - SMT
Mike - SMT

Reputation: 15226

First lets clean up the code to be more PEP8 friendly and also change import so we are not importing *. By importing * you run the risk of overwriting imports and built in methods.

I would create your widget outside of your function and then replace your loop containing sleep() with a function that can call itself and uses after() as sleep will block your mainloop rendering your GUI useless and frozen until all the sleeping has completed. after() is used to avoid this problem.

import tkinter as tk
from tkinter import scrolledtext

root = tk.Tk()
root.title('test_loop')
root.geometry('750x625')
root.configure(background='ivory3')
textw = scrolledtext.ScrolledText(root, width=40, height=25)
textw.grid(column=0, row=1, sticky='nsew')
textw.config(background='light grey', foreground='black', font='arial 20 bold', wrap='word', relief='sunken', bd=5)


def show_msg(count=None):
    if count is not None:
        if count <= 5:
            txt = 'This is {} times though the loop.'.format(count)
            textw.delete('1.0', 'end')
            textw.insert('end', txt)
            count += 1
            root.after(2000, lambda: show_msg(count))
    else:
        show_msg(1)


tk.Button(root, text='display_log', bg='light grey', width=15, font='arial 12', relief='raised', bd=5,
          command=show_msg).grid(row=0, column=0)

root.mainloop()

Results:

enter image description here

If you want to keep all your logs on the screen (assuming you want to as normally logs should all be kept) I would remove the delete command and then add a \n to the text so each log is on a new line.

Simply edit the function like this:

def show_msg(count=None):
    if count is not None:
        if count <= 5:
            txt = 'This is {} times though the loop.\n'.format(count)
            # textw.delete('1.0', 'end')
            textw.insert('end', txt)
            count += 1
            root.after(2000, lambda: show_msg(count))
    else:
        show_msg(1)

Results:

enter image description here

Let me know if you have any questions.

Upvotes: 4

Bryan Oakley
Bryan Oakley

Reputation: 385800

You are sleeping after inserting the text, and then deleting the text before the next time you call update. The call to update needs to happen after inserting the text, not before.

Upvotes: 1

Related Questions