36

I wrote a Python script that does some task to generate, and then keep changing some text stored as a string variable. This works, and I can print the string each time it gets changed.

I can get the Label to display the string for the first time, but it never updates.

Here's my code:

from tkinter import *

outputText = 'Ready'
counter = int(0)

root = Tk()
root.maxsize(400, 400)

var = StringVar()

l = Label(root, textvariable=var, anchor=NW, justify=LEFT, wraplength=398)
l.pack()

var.set(outputText)

while True:
    counter = counter + 1
    outputText = result
    outputText = result
    outputText = result
    if counter == 5:
        break

root.mainloop()

The Label will show Ready, but won't update to change that to the strings as they're generated later.

After a fair bit of googling and looking through answers on this site, I thought the solution might be to use update_idletasks. I tried putting that in after each time the variable was changed, but it didn't help.

nbro
  • 15,395
  • 32
  • 113
  • 196
Tom
  • 395
  • 1
  • 3
  • 7
  • 2
    Possible duplicate of [Making python/tkinter label widget update?](http://stackoverflow.com/questions/1918005/making-python-tkinter-label-widget-update) – Lafexlos Jan 15 '16 at 12:19

3 Answers3

39

The window is only displayed once the mainloop is entered. So you won't see any changes you make in your while True block preceding the line root.mainloop().


GUI interfaces work by reacting to events while in the mainloop. Here's an example where the StringVar is also connected to an Entry widget. When you change the text in the Entry widget it automatically changes in the Label.

from tkinter import *

root = Tk()
var = StringVar()
var.set('hello')

l = Label(root, textvariable = var)
l.pack()

t = Entry(root, textvariable = var)
t.pack()

root.mainloop() # the window is now displayed

I like the following reference: tkinter 8.5 reference: a GUI for Python


Here is a working example of what you were trying to do:

from tkinter import *
from time import sleep

root = Tk()
var = StringVar()
var.set('hello')

l = Label(root, textvariable = var)
l.pack()

for i in range(6):
    sleep(1) # Need this to slow the changes down
    var.set('goodbye' if i%2 else 'hello')
    root.update_idletasks()

root.update Enter event loop until all pending events have been processed by Tcl.

martineau
  • 119,623
  • 25
  • 170
  • 301
Gary Kerr
  • 13,650
  • 4
  • 48
  • 51
  • Thanks. So if I understand you correctly, if I put mainloop before the While True block, the label will be displayed immediately to start with before that block gets executed. But then it won't update based on what's in the While True block, since that lies outside the mainloop, will it? It doesn't seem to be, in any case... – Tom Apr 08 '10 at 21:32
  • **split into 2 comments because of the character limit** So what would I need to do? It seems that if I put mainloop before the While True block nothing in the While True block will be displayed... whereas if I put it afterwards, it will do everything in the block before displaying... I need some middle ground. Can I write mainloop multiple times? Like, after each time I want the display to update? – Tom Apr 08 '10 at 21:33
  • Well, tried that and it didn't work. I suppose I could duplicate the entire thing each time I wanted an update... like, close the old label and just make a new one in its place, instead of worrying about keeping one and updating it... but that seems such a messy way to go about things. – Tom Apr 08 '10 at 21:40
  • Has my second example helped? – Gary Kerr Apr 08 '10 at 22:02
  • Yes, it has. Many thanks. So much googling and I can't believe I didn't run across 'root.update'. Oh well. – Tom Apr 08 '10 at 22:17
  • `dir(root)` shows all attributes of `root`. Then `help(root.update)` shows the `__doc__` string for the method. – Gary Kerr Apr 08 '10 at 22:31
  • 7
    You should avoid calling `update` unless you are certain of what it does. Instead, call `update_idletasks`. The former causes all events to be processed, the latter only processes "idle" tasks such as redrawing windows. When you call `update` you are creating a new, nested event loop which can be dangerous. I've modified the answer to call the proper method. – Bryan Oakley May 08 '11 at 14:24
9

Maybe I'm not understanding the question but here is my simple solution that works -

# I want to Display total heads bent this machine so I define a label -
TotalHeadsLabel3 = Label(leftFrame)
TotalHeadsLabel3.config(font=Helv12,fg='blue',text="Total heads " + str(TotalHeads))
TotalHeadsLabel3.pack(side=TOP)

# I update the int variable adding the quantity bent -
TotalHeads = TotalHeads + headQtyBent # update ready to write to file & display
TotalHeadsLabel3.config(text="Total Heads "+str(TotalHeads)) # update label with new qty

I agree that labels are not automatically updated but can easily be updated with the

<label name>.config(text="<new text>" + str(<variable name>))

That just needs to be included in your code after the variable is updated.

adiga
  • 34,372
  • 9
  • 61
  • 83
Brian Steinke
  • 91
  • 1
  • 1
3

This is the easiest one , Just define a Function and then a Tkinter Label & Button . Pressing the Button changes the text in the label. The difference that you would when defining the Label is that use the text variable instead of text. Code is tested and working.

    from tkinter import *
    master = Tk()
    
    def change_text():
        my_var.set("Second click")
    
    my_var = StringVar()
    my_var.set("First click")
    label = Label(mas,textvariable=my_var,fg="red")
    button = Button(mas,text="Submit",command = change_text)
    button.pack()
    label.pack()
    
    master.mainloop()