在Python TkInter中更新标签文本

5
有没有可能创建一个使用字符串和变量作为文本的TkInter标签呢?
例如:
name = "bob"
Label(root, text="hello, my name is "+name)

但是,不仅在标签创建时使标签文本向上移动,而且在“名称”更改时更新文本,而无需引用标签实例本身。

有人知道这是否可能吗?

3个回答

8
您需要告诉标签以某种方式进行更改。
以下是一个示例。标签的文本是一个名为textStringVar文本变量,您可以使用text.set()随时更改它。
在示例中,当您单击复选框时,命令change会告诉标签更改为新值(此处简化为两个值,oldnew)。
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()

5
您无法完全做到您所要求的--您无法同时将静态字符串和变量与标签关联。有些事情可以让你达到想要的效果,但你只是增加了复杂性而没有真正的收益。例如,您可以将 StringVar 的实例分配给 Label widget 的 textvariable 属性。这样做,任何对变量的更新都会更新标签。然而,你最终需要调用一个函数来更新变量,所以你并没有真正从直接调用一个函数来更新标签中得到什么好处。
另一种选择是使用两个标签--一个用于静态文本,另一个用于变量。把它们并排放置,没有边框,这样用户就不会注意到。然后,当您更新变量时,您将获得所需的效果。然而,你仍然必须调用一个函数来设置变量,所以你并没有真正获得太多。
还有另一种选择是使用两个 StringVar 的实例--一个用于标签,另一个用于名称。您可以在名称变量上设置跟踪,这样当它改变时,您自动用静态字符串和名称变量的值更新另一个变量,这将导致标签自动更新。然而,再次强调,你必须调用一个函数来启动一切。
因此,正如您所看到的,虽然有选择,但它们都在你的代码中增加了复杂性,而没有真正的收益。这些其他方法唯一优越的地方是当该值需要同时出现在多个小部件中时。在这种情况下,您可以将变量与两个或更多小部件相关联,并且单个函数调用将更新所有相关小部件。

是的 - 标准的Tkinter可以做到这一点。感谢您的认可。您对不断增长的复杂性所需的成本的提醒是公正的。其余的只是找到完成客户任务的方法,并在15个小时后说:“是的 - 可以实现。它有效。” - user3666197
9
@user3666197:我不知道您的评论想表达什么意思。 - Bryan Oakley
这段文字没有任何代码,对于初学者来说并不清楚。实际上只需要创建一个label标签,例如 label = Label(root, text="hello, my name is "+name),然后通过 name = 'whatever' 更改名字变量,最后使用 label.set("hello, my name is "+name) 设置 label 标签的内容。但是这个答案在没有代码示例的情况下相对隐晦。 - questionto42
1
@questionto42:不,我的答案没有错。我在第一段中提到了不引用小部件的问题。您可以使用变量,但是那么您必须有对变量的外部引用,这与具有对小部件的引用没有什么区别。无论哪种情况,您都需要引用某些东西,而使用变量会增加一个没有实际好处的额外对象。 - Bryan Oakley
好的,我知道你的意思只是“无法同时将静态字符串和变量关联到标签”,这使得它很复杂。即使更改变量名称,仍需要在其之间添加步骤以将其放入tkinter变量中。这意味着您的答案是唯一回答该问题的答案(这就是Stack Overflow的用途),尽管其他答案使代码更清晰,如果需要解决方法,则需要将静态和变量部分合并为一个更改。 - questionto42
显示剩余2条评论

5

是的——标准的Tkinter <变量>机制可以实现这一点:

有一个Tkinter StringVar()(类似的还有IntVar()DoubleVar()BoolVar())对象构造器,它准备了一个智能对象,可以在Tkinter小部件中随后用于此目的。

您可以使用.set() / .get()方法来操纵这种对象的值。

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

当在 <变量> 中赋予新值时,标签文本会相应更改

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

注意:高级<变量>工具

您可能还想了解一些更高级的Tkinter变量工具。与Tkinter变量相关联的还有更强大的工具,称为trace-er(s),它们将Tkinter系统设置为“监视”对“追踪”变量的任何更改,并且这可以关联进一步的自动响应活动,在追踪事件类型发生时自动启动。

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

该工具可以帮助您创建GUI工具箱策略,使其更加高效、事件驱动、全面自我反省,并在Tkinter.mainloop()调度程序下进行监督。
如何组合它呢?正如abarnert所建议的那样,自动化版本在原则上可能如下所示。
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

1
你的大胆“YES”有点误导人。严格来说,对于这个问题的答案是“NO”。该问题询问的是当值既有常量部分又有变量部分时是否自动更新。而“YES”仅适用于只有变量部分的情况。 - Bryan Oakley
尊敬的Bryan,阅读帖子后,你提出的两个反对意见都被涉及到了,甚至包括完整的代码配方、逐步说明和注释。Bryan,你的专业洞察力绝对不仅仅是批评其他发帖人的写作风格,而是要为(可能是新的)其他人提供可读的解释,这些人很可能比你更少接触Tkinter,并且有着不同的专业方向。如果你真的无法抵制,那就帮助并改进解释。然而,请保持微笑,享受美好的周日下午。 - user3666197
1
@BryanOakley:好吧,答案是“不行,除非你使用Tk的StringVar而不是普通变量”...但既然现在展示了如何使用该StringVar以一种可能完全合理的方式来近似OP所希望的内容,我不知道这是否是一个问题。 - abarnert
@user3666197:就像我说的那样,答案是误导性的。问题字面上是“有没有可能创建一个TkInter标签,使用字符串和变量作为文本?”(强调我的)。对于这个字面意思的问题,答案是不行的。我发表评论是为了让答案更好。如果你要用大而粗的字母简单地回答“是”,我认为它需要是字面上正确的。但事实并非如此。是的,答案详细介绍了如何做到用户想要的,这使它成为一个好答案。让它成为一个伟大的答案的是不要过于强调“是”。 - Bryan Oakley
@abarnert:“不,除非您使用Tk StringVar而不是常规变量”也是误导性的。问题是关于组合文字字符串和自动更新变量,您无法使用StringVar来完成这个任务。这正是我认为答案具有误导性的原因。虽然有解决问题的方法,但对于所提出的问题,即使使用StringVar,回答也不是毫无疑问的“是”。 - Bryan Oakley
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接