简体   繁体   中英

Update Label Text in Python TkInter

Is there any possible way to create a TkInter label that uses a string and a variable as the text?

For example:

name = "bob"
Label(root, text="hello, my name is "+name)

But instead of that only making the text of the label to the above on label creation, to have it update the text when "name" changes without having to reference the label instance itself.

Does anyone know if this is possible?

You must tell the label to change in some way.

Here you have an example. The text of the label is a textvariable text defined as a StringVar which can be changed whenever you want with text.set() .
In the example, when you click the checkbox, a command change tells the label to change to a new value (here simplified to take two values, old and new )

from Tkinter import Tk, Checkbutton, Label
from Tkinter import StringVar, IntVar

root = Tk()

text = StringVar()
text.set('old')
status = IntVar()

def change():
    if status.get() == 1:   # if clicked
        text.set('new')
    else:
        text.set('old')


cb = Checkbutton(root, variable=status, command=change)
lb = Label(root, textvariable=text)
cb.pack()
lb.pack()

root.mainloop()

You cannot do precisely what you ask -- you can't associate both a static string and a variable to a label at the same time. There are things you can do to get the desired effect, but all you're doing is adding complexity with no real gain. For example, you can assign an instance of StringVar to the textvariable attribute of the Label widget. When you do that, any update to the variable will update the label. However, you end up having to make a function call to update the variable, so you don't really gain anything over making a function call to update the label directly.

Another option is to use two labels -- one for the static text and one for the variable. Put them side-by side with no border so the user won't notice. Then, when you update the variable you'll get the desired effect. However, you're still having to make a function call to set the variable so you don't really gain much.

Yet another option is to use two instances of StringVar -- one for the label, and another for the name. You can put a trace on the name variable so that when it changes, you automatically update the other variable with the static string and the value of the name variable, and that will cause the label to be automatically updated. Again, however, you're having to make a function call to put everything in motion

So, as you can see, there are options, but they all add complexity to your code with no real gain over simply updating the label directly. The only time these other methods gain you an advantage is when the value needs to appear in more than one widget at once. In that case you can associate the variable with two or more widgets, and a single function call will update all associated widgets.

Yes -- standard Tkinter < variable >-s mechanics does that:

There is a Tkinter StringVar() ( and similarly IntVar() , DoubleVar() , BoolVar() ) object constructor, that prepares a smart object that is ready to be later used for this very purpose in Tkinter Widgets.

You may use .set() / .get() methods for manipulating with such object's value(s).

name              = StringVar()        # this creates a Tkinter object
name.set( "bob" )                      # .set() assigns / .get() retrieves
L = Label( root, textvariable = name ) # makes the <name> used in Label Widget

Label text gets changed right by a new value gets assigned in < variable >

name.set( "alice" )                    # .set() assigns a new value -> promoted
print L['text']                        # show, a value has been promoted in L

FYI: Advanced < variable >-s' Tools

You may also want to know about a more advanced tools for Tkinter variables. There are also more powerful tools associated with Tkinter variables -- called trace -er(s) -- which set the Tkinter system to "watch" any change to a "traced" variable and this can associate further automated responsive activities, automatically launched upon a traced-event-type.

aWriteTraceID = name.trace_variable( "w", f2CallOnWriteAccessToTracedVariable )
aRead_TraceID = name.trace_variable( "r", f2CallOnRead_AccessToTracedVariable )
aDel__TraceID = name.trace_variable( "u", f2CallOnDel__AccessToTracedVariable )

name.trace_vinfo()                        # show all associated <<Tracers>>

>>> name.trace_vinfo()
[('u', '12945528f2CallOnDel__AccessToTracedVariable'),
 ('r', '12251384f2CallOnRead_AccessToTracedVariable'),
 ('w', '12760924f2CallOnWriteAccessToTracedVariable')
]

name.trace_vdelete( aRead_TraceID )       # delete an identified <<Tracer>>
name.trace_vdelete( aWriteTraceID )       # delete an identified <<Tracer>>

del( name )                               # del() makes name undefined
# so this will "auto-launch" the last, still active <<Tracer>>
# you assigned above -- the function f2CallOnDel__AccessToTracedVariable()

This instrumentation helps you create your GUI toolbox strategies very powerful for an efficient, event-driven, fully self-reflecting layered [Model-Visual-Controller], supervised under the hood of the Tkinter.mainloop() scheduler

How to put it together?

As abarnert has proposed, the automated version may look in principle like this

name = StringVar()                         # a pure name holder
show = StringVar()                         # a post-processed text

L = Label( root, textvariable = show )     # L will display a post-processed string
L.pack()                                   # L goes into GUI framework's geometry manager

#                                          # prepare the <<Handler>> function
def autoProcessAndPropagateOnNameVarCHANGE( p1, p2, p3, p4 = name, p5 = show ):
    #                                      # this function will get called
    #                                      # upon WRITE-ACCESS <<Tracer>>
    #
    # .set( a post-processed value ) into [show], that is connected to GUI[Label]
    p5.set( "Hello, " + p4.get() )         
    #                                      # Always be carefull not to fire
    #                                      # an unstoppable chain-reaction ;)
    #                                      # of <<Tracer>>-related events
    #                                      # as more <<Tracer>>-s get used

#                                          # create <<Tracer>> / <<Handler>> pair
aWriteTraceID = name.trace_variable( "w", autoProcessAndPropagateOnNameVarCHANGE )

# -------------------------------------------------------------------------------
# test <<Tracer>>:
name.set( "Craig" )                        # <<Tracer>>-watched WRITE-ACCESS
# test <<Tracer>> result: GUI Label L shall show "Hello, Craig" -----------------

# -------------------------------------------------------------------------------
# erase all <<Tracer>>-s assigned:
name.trace_vinfo()                         # initial state of <<Tracer>>-s

for aTracerRECORD in name.trace_vinfo():
    name.trace_vdelete( aTracerRECORD[0], aTracerRECORD[1] )

# erase [[[DONE]]] --------------------------------------------------------------
name.trace_vinfo()                         # final   state of <<Tracer>>-s

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM