5

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?

3 Answers 3

8

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()
Sign up to request clarification or add additional context in comments.

Comments

5

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.

7 Comments

Yes -- standard Tkinter .... does that. Appreciate you say the same. Your notice on a cost of growing complexity, that is needed to solve the Customer Task is fair. The rest just finds the way, how to make the Customer Task done and finally, after 15 hours say, Yes -- it is possible. It works.
@user3666197: I have no idea what your comment is trying to say.
This text - without any code - does not make it clear enough for a beginner that you just need to make a label label = Label(root, text="hello, my name is "+name), then change the name variable with name = 'whatever' and then set the label with label.set("hello, my name is "+name). Which meant by this answer, but quite hidden in a text without code examples.
@questionto42: label widgets do not have a set method.
@questionto42: no, my answer isn't wrong. I addressed not referencing the widget in the first paragraph. You can use a variable, but then you have to have an external reference to the variable which is no more difficult than having a reference to the widget. In either case, you need a reference to something, and using a variable adds an extra object with no real benefit.
|
5

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

10 Comments

The second half of this would be really useful if you showed how to write that f2CallOnWriteAccessToTracedVariable function so that it does what he wants. In particular, he needs a StringVar attached to the Label, and a separate variable name, and whenever name is updated it has to set the other variable appropriately. As written, your answer hints that might be possible, but doesn't show him how to do it.
@abarnert Correct. Finally added a step-by-step recipe in a belief, it may inspire both an immediate re-use and a further own research into additional powers of Tkinter for a professional grade real-time UI control tools.
Your bold "YES" is a bit misleading. Strictly speaking, the answer to the question is "NO". The question asks about automatically updating when the value has both a constant part and a variable. The "YES" applies only to having only a variable.
With all due respect, Bryan, upon reading the post, neither of your objections remained untouched, having even the full code-recipe step-by-step & comments. Your professional insight, Bryan, definitely goes much farther than to just mob other poster's style of writing an explanation readable also to (incl. possibly new) other people here, with most probably other professional direction and with lower exposure to Tkinter, than you have. Help & improve the explanation, if you really cannot resist. However, please, keep smiling & enjoy the great Sunday afternoon.
@BryanOakley: Well, the answer is "No, unless you use a Tk StringVar instead of a regular variable"… but since it now shows how to use that StringVar to approximate what the OP was hoping for in a way that may well be perfectly reasonable, I don't know that that's a problem.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.