views:

422

answers:

1

I wrote a python script that does some stuff 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.

Problems have arisen while trying to display that output in a GUI (just as a basic label) using tkinter.

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

This is really the first time I have tried to use tkinter, so it's likely I'm making a foolish error. What I've got looks logical to me, but I'm evidently going wrong somewhere!

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

    #do some stuff that generates string as variable 'result'

    outputText = result

    #do some more stuff that generates new string as variable 'result'

    outputText = result

    #do some more stuff that generates new string as variable 'result'

    outputText = result

    if counter == 5:
        break

root.mainloop()

I also tried:

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

    #do some stuff that generates string as variable 'result'

    outputText = result
    var.set(outputText)

    #do some more stuff that generates new string as variable 'result'

    outputText = result
    var.set(outputText)

    #do some more stuff that generates new string as variable 'result'

    outputText = result
    var.set(outputText)

    if counter == 5:
        break

root.mainloop()

In both cases, 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.

It also seems possible I am meant to be using trace and callback somehow to make all this work...but I can't get my head around how that works (I tried, but didn't manage to make anything that even looked like it would do something, let alone actually worked).

I'm still very new to both python and especially tkinter, so, any help much appreciated but please spell it out for me if you can :)

+1  A: 

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: http://infohost.nmt.edu/tcc/help/pubs/tkinter/


EDIT: 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()

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

PreludeAndFugue
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
**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
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
Has my second example helped?
PreludeAndFugue
Yes, it has. Many thanks. So much googling and I can't believe I didn't run across 'root.update'. Oh well.
Tom
`dir(root)` shows all attributes of `root`. Then `help(root.update)` shows the `__doc__` string for the method.
PreludeAndFugue