Hi,

I have a UI built in Tkinter. The user can type in some inputs and hit "Run" When the "Run" occurs, a program executes that could take 30 seconds or more! The problem is that this blocks the graphics updating.

At the beginning, I set a Label to "Running program..." and at the end I set the Label to "Finished running." Also, throughout running the program, I set the Label to various things like "Finished task X, starting task Y"

Anyone experts know the standard way to do something like this?

You guys are so smart compared with me - I'm new to Tkinter.

Thanks!

It would have been better to understand your problem if you had posted your code here.
Sure I'll help.

Here's an example. You'll never actually see "Running command..." because the operation blocks the display from updating until it's done.

import time
from Tkinter import *

class MyApp:
    def __init__(self, parent):
        self.myParent = parent  ### (7) remember my parent, the root
        self.myContainer1 = Frame(parent)
        self.myContainer1.pack()

        self.button1 = Button(self.myContainer1)
        self.button1.configure(text="Button")
        self.button1.pack()
        self.button1.bind("<Button-1>", self.button1Click)

        self.lbl = Label(self.myContainer1)
        self.lbl.pack()

        self.button2 = Button(self.myContainer1)
        self.button2.configure(text="Quit", background="red")
        self.button2.pack()
        self.button2.bind("<Button-1>", self.button2Click)


    def button1Click(self, event):    ### (3)
        # expensive process here
        # simulated by time.sleep
        self.lbl.configure(text='Running command...')
        time.sleep(4)
        self.lbl.configure(text='Finished running command...')

    def button2Click(self, event):  ### (5)
        self.myParent.destroy()     ### (6)


root = Tk()
myapp = MyApp(root)
root.mainloop()

This works better:

def button1Click(self, event):    ### (3)
        # expensive process here
        # simulated by time.sleep
        self.lbl.configure(text='Running command...')
        self.lbl.update()
        time.sleep(4)
        self.lbl.configure(text='Finished running command...')

That doesn't work - it complete freezes the program...

You can use update_idletasks()

import time
from Tkinter import *
 
class MyApp:
    def __init__(self, parent):
        self.myParent = parent  ### (7) remember my parent, the root
        self.myContainer1 = Frame(parent)
        self.myContainer1.pack()
 
        self.button1 = Button(self.myContainer1)
        self.button1.configure(text="Button")
        self.button1.pack()
        self.button1.bind("<Button-1>", self.button1Click)
 
        self.lbl = Label(self.myContainer1)
        self.lbl.pack()
 
        self.button2 = Button(self.myContainer1)
        self.button2.configure(text="Quit", background="red")
        self.button2.pack()
        self.button2.bind("<Button-1>", self.button2Click)
 
 
    def button1Click(self, event):    ### (3)
        # expensive process here
        # simulated by time.sleep
        self.lbl.configure(text='Running command...')
        self.myContainer1.update_idletasks()
        time.sleep(4)
        self.lbl.configure(text='Finished running command...')
 
    def button2Click(self, event):  ### (5)
        self.myParent.destroy()     ### (6)
 
 
root = Tk()
myapp = MyApp(root)
root.mainloop()

Awesome! Thanks!

Please mark the thread "Solved". Be aware that some people do not like using update_idletasks(), and there are at least two other ways; using .after() which does not require an update, or a Tkinter StringVar() which updates whenever the text is changed.

import time
from Tkinter import *
 
class MyApp:
    def __init__(self, parent):
        self.myParent = parent  ### (7) remember my parent, the root
        self.myContainer1 = Frame(parent)
        self.myContainer1.pack()
 
        self.button1 = Button(self.myContainer1)
        self.button1.configure(text="Button")
        self.button1.pack()
        self.button1.bind("<Button-1>", self.button1Click)
 
        self.lbl = Label(self.myContainer1)
        self.lbl.pack()
 
        self.lbl2_text = StringVar()
        self.lbl2_text.set("lbl2")
        self.lbl2 = Label(self.myContainer1, textvariable=self.lbl2_text)
        self.lbl2.pack()
 
        self.lbl3 = Label(self.myContainer1)
        self.lbl3.pack()
 
        self.button2 = Button(self.myContainer1)
        self.button2.configure(text="Quit", background="red")
        self.button2.pack()
        self.button2.bind("<Button-1>", self.button2Click)
 
 
    def button1Click(self, event):    ### (3)
        # expensive process here
        # simulated by time.sleep
        self.lbl2_text.set("updated also")
        self.myContainer1.after(100, self.lbl3.configure(text='lbl3 Running'))

        self.lbl.configure(text='Running command...')
        self.myContainer1.update_idletasks()
        time.sleep(4)
        self.lbl.configure(text='Finished running command...')
 
    def button2Click(self, event):  ### (5)
        self.myParent.destroy()     ### (6)
 
 
root = Tk()
myapp = MyApp(root)
root.mainloop()

Yeah but the previous code gives more promising result that the latter.
Similar to that:

from Tkinter import*
import time
class myapp(Frame):
    def __init__(self,master=None):
        Frame.__init__(self,master)
        self.grid()
        self.weeds()
        
    def weeds(self):
        self.button=Button(self,text='Button',command=self.onclick).grid()        
        self.var=StringVar()
       
        self.msg=Label(self,textvar=self.var)
        self.msg.grid()
    def onclick(self):        
        self.var.set("Running command..")
        self.msg.update_idletasks()#remember to update "idle tasks"-**
        time.sleep(1.5)            #otherwise your message waits until
        self.nest1()               #mainloop 
    def nest1(self):
        self.var.set("Still Running.")
        self.msg.update_idletasks()#**
        time.sleep(2)
        self.nest2()
    def nest2(self):
        self.var.set("Not yet.")
        self.msg.update_idletasks()#**
        time.sleep(1.5)
        self.nest3()
    def nest3(self):
        self.var.set("Finished")
        self.msg.update_idletasks()#**
        
        
        
root=Tk()
APP=myapp(master=root)
APP.mainloop()
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.