2

It's an extremely simple Python Tk program. I can't seem to stop a simple problem and I am sure I am missing something easy.

I make a label:

myLabelText = StringVar()
myLabelText.set("Something kinda long")
myLabel = Label(frame, textvariable=myLabelText).pack()

Later in the same program I want to update that label to say "Foo"...

myLabelText.set("Foo")
frame.update_idletasks()

The label now looks like "Fooething kinda long" The goal would be to just have "Foo" and clear the rest of the label text.

I tried to set the label to a long string of spaces but for some reason that's not clearing the text in that field. What is the right way to do this?


Edit

Here is a complete example that demonstrates my problem.

from Tkinter import *
import tkFileDialog, Tkconstants
import time
import urllib2

def main():
    " Controlling function "

    root = Tk()
    app = App(root)
    root.mainloop()

class App:
    " Class for this application "

    def __init__(self, master):

        # Setup the window
        frame = Frame(master, width=400, height=200)
        frame.pack()
        frame.pack_propagate(0)
        self.frame = frame
        self.master = master

        # Start Button
        self.button = Button(frame, text='Start', bg="#339933", height=3, width=10, command=self.start)
        self.button.pack()

        # Label
        self.operation_action_text = StringVar()
        self.operation_action_text.set("Waiting on user to click start...")
        self.operation_action = Label(frame, textvariable=self.operation_action_text)
        self.operation_action.pack()


    def start(self):
        " Change the label "

        # Do something and tell the user
        response = urllib2.urlopen('http://www.kennypyatt.com')
        json_string = response.read()
        self.operation_action_text.set("Something kinda long")
        self.frame.update_idletasks()
        time.sleep(2)

        # Do something else and tell the user
        response = urllib2.urlopen('http://www.kennypyatt.com')
        json_string = response.read()
        self.operation_action_text.set("ABCDEFGHI")
        self.frame.update_idletasks()
        time.sleep(2)

        # Do a third thing and tell the user
        response = urllib2.urlopen('http://www.kennypyatt.com')
        json_string = response.read()
        self.operation_action_text.set("FOO")
        self.frame.update_idletasks()

        return

main()
Kenny Pyatt
  • 363
  • 1
  • 4
  • 17
  • I am not posting this as an answer because I have never worked with Tkinter so I may be wrong but [this code](http://pastie.org/4546378) does what you need. – RanRag Aug 18 '12 at 20:51
  • @RanRag thanks for the reply but that is what I am doing and it's not clearing the label. The text that was there before stays. It looks like the effect of blitting without redrawing the background. – Kenny Pyatt Aug 18 '12 at 21:34
  • 2
    Write a complete program that illustrates the problem. There must be more to the story that what you're explaining, because what you're explaining isn't what Tkinter normally does. – Bryan Oakley Aug 18 '12 at 23:34
  • @BryanOakley your probably right... It feels like what I am doing should work. I'll see if I can make a minimal example. – Kenny Pyatt Aug 19 '12 at 15:20
  • @BryanOakley I've added an example. Looking forward to learning from the masters. – Kenny Pyatt Aug 19 '12 at 17:40

2 Answers2

2

The first thing you will want to consider doing differently is separating:

myLabel = Label(frame, textvariable=myLabelText).pack()

into

myLabel = Label(frame, textvariable=myLabelText)
myLabel.pack()

Please read →this link← for information concerning this.


To update a Label's text you do not need a control variable.
You can change the text in one of two ways:

myLabel.configure(text='new text')

or

myLabel['text'] = 'new text'

You can inspect the second example →here←
to further your understanding of control variables in regard to this topic.


update_idletasks() is not required for updating the text of a Label widget.
I have only found a need for using this when working with a window's geometry.
One example of this is centering a window.


Based on the edit:

Creating your root and app as local variables of a global function is very unorthodox.
Try a rewrite based on the structure seen →here←.

You will want to avoid using time.sleep() with a tkinter app; because it's in conflict with the event loop. Try splitting your single method into multiple methods, and then you can use Tk's after(milliseconds, method) method at the end of each to gracefully move to the next, after x milliseconds.

I'd also consider removing the return from your method.

Community
  • 1
  • 1
Honest Abe
  • 8,430
  • 4
  • 49
  • 64
  • pack()ing on the second line explains why I was having to use the StringVar() textvariable thing in the first place. Thanks! Unfortunately that doesn't seem to impact my issue at all. I suspect I don't understand what Tk is doing under the hood so I've approached this with the wrong paradigm. – Kenny Pyatt Aug 19 '12 at 17:42
  • @Honest_Abe Regarding the time.sleep, I wanted to make sure you could see the behavior when you ran it. I'm under the impression that the return isn't doing anything. I was brainwashed by my first CS professor to always implicitly return. Removing it didn't change anything. – Kenny Pyatt Aug 19 '12 at 20:44
  • @KennyPyatt The only thing I thought might have a chance of resolving the issue was the restructuring of the class. If that doesn't help, I'm clueless as to what would be causing the issue. The bit about the sleep and return was just general advice. – Honest Abe Aug 19 '12 at 21:02
  • I appreciate your help... I tried refactoring but I'm pretty sure it's doing the same with fewer lines of code. Your way is clean and I like it better than what I had. Thanks. – Kenny Pyatt Aug 19 '12 at 21:13
  • @Honest_Abe I just dug this script back out and I noticed something different this time. The label seemed to be dynamically re-sizing itself. I set a width on the label and the behavior stopped. I still feel like I'm missing the spirit of how I was supposed to do this. I'm going to award the points to you since your answers were more inline with the spirit of what I needed to do. – Kenny Pyatt Nov 18 '12 at 23:05
0

I know post is old but I found a solution to your problem. Here's a small code explaining a solution:

global y
y=0
top=TopLevel()

def_newlabel():
  global y,od2,odpuni
  if y > 0:
    od2.destroy()
    odpuni.destroy()
  odpuni = Label(top, text="blablabla",bg="lightskyblue")
  odpuni.grid(row=7, column= 3, sticky="E")
  od2 = Label(top, text="blabla",bg="lightskyblue")
  od2.grid(row=7, column= 4, sticky="W")
  y=y+1

So basicaly, all you have to do is get counter out of function,set it to 0 and when you get to def_newlabel(). It will check first if your counter is bigger than 0. If its not , it will continue with program. If you already used your label ,your counter will be bigger than 0 and trigger "IF Loop" and delete your label text. Only way I managed to get it work.

Greetings, Luka.