【问题标题】:tkinter Label updating but not correctlytkinter 标签更新但不正确
【发布时间】:2016-12-23 10:31:00
【问题描述】:

使用 Python 3.5。我有一个tkinter 表格。用户单击按钮将许多文件导入Listbox。另一个按钮循环遍历文件并从中读取和提取数据。

我在表单上有一个Label,表示循环的状态。在大多数情况下,该状态按预期工作,只是在末尾添加了额外的字符。我不知道这些字符是从哪里来的。我也将print()Label 相同的内容返回到屏幕,而print() 显示的正是它应该显示的内容。

我的问题是为什么我的Label 没有显示正确的字符串?

我的代码,大大缩短了:

class tk_new_db:
    def __init__(self, master):
        self.master = master  # sets 'root' to the instance variable 'master'
        self.var_text_2 = StringVar()
        self.var_text_2.set('STATUS: Active')
        self.label_6 = Label(master, textvariable=self.var_text_2,
                             font=self.font_10)
        self.label_6.grid(row=15, sticky=W, padx=15)

    def execute_main(self):  # extract data from files
        file_num = 0
        nf = len(self.listbox_1.get(0, END))
        for fr in li:
            file_num += 1
            print('STATUS: Extracting Loads from File '
                  '{} in {}'.format(file_num, nf))
            self.var_text_2.set('STATUS: Extracting Loads from File '
                                '{} in {}'.format(file_num, nf))
            self.master.update_idletasks()

print() 正在写以下内容: STATUS: Extracting Loads from File 1 in 5

Label 正在写以下内容: STATUS: Extracting Loads from File 1 in 5 nce...

它总是在表单上添加' nce...'

编辑:

我确实在程序的前面使用了self.var_text_2' nce...' 看起来像是前一个字符串的片段。从那以后,我尝试以两种不同的方式重置变量,但我仍然得到相同的结果。

    self.var_text_2.set('STATUS: Checking .F06 Files for Convergence...')
    self.master.update_idletasks()
    self.var_text_2.__del__()

    self.var_text_2.set('STATUS: Checking .F06 Files for Convergence...')
    self.master.update_idletasks()
    self.var_text_2.set('')

如何正确删除StringVar() 以供重复使用?

【问题讨论】:

  • 也许在此之前有一些文本以 'nce' 结尾。您可以在更改标签文本后尝试self.master.update_idletasks(),看看是否修复。
  • 你的代码太短了。没有什么可以解释你所说的正在发生的事情。请edit您的问题并将代码替换为MCVE
  • 没有特殊的方法可以清除StringVar。每次调用其set() 方法时,作为参数传递的值将完全替换它之前的任何值(并且将其设置为textvariable 选项的任何Label 实例的文本将自动更新)。像StringVar 这样的变量类都有一个trace() 方法——这(解释得很差)here——你可以通过安排每次改变它的值时调用的东西来发现正在发生的事情.
  • 我读过的所有地方都建议不要使用update(),但是,它实际上可以正确更新标签。我不知道为什么update_idletasks() 不能正常工作。我的情况似乎很基本。
  • 这是一个多线程程序吗?大多数 GUI,我认为这包括 tk,都不是线程安全的。您只能从主线程更改小部件的状态。如果您尝试,可能会发生一些非常奇怪的事情。

标签: python tkinter label


【解决方案1】:

我想我可以解释一下。 Root.mainloop 反复调用 root.update。 Root.update 在“主”事件队列上执行任务。简而言之,它仅在事件队列为空 检查文件事件(在非 Windows 上)、window-gui 事件和计时器事件后执行 idletasks。 Idletasks,没有很好的文档记录,但似乎主要是屏幕更新任务,永远不会添加到主事件队列中。因此,空闲任务可能会无限期地保持未完成状态。 Root.update_idletasks 的存在是为了强制执行 idletasks。

当 mainloop 运行时,在 update 运行的任务中调用 update 通常是不必要的,而且可能更糟。这只是冒险专家的东西。因此,您已经阅读了警告(假设您正在运行 mainloop)。

当 mainloop 没有运行并且 update 没有被重复调用时,要么是因为你从未调用过 mainloop,要么是因为你用一个长时间运行的循环阻塞了它,那么你可能必须自己调用 update。您似乎已经发现,完全处理 StringVar 更新的部分是一个主要事件,而不仅仅是一个空闲任务。

我同情您希望使用 for 循环执行重复任务的愿望,但目前这样做意味着您自己负责事件处理。我希望将来可以让 'async for'(3.5 中的新功能)与 Tk.mainloop 互操作,但这并不像我希望的那么容易。

同时,您可以将 for 循环的主体放入回调中,并使用 root.after 进行循环。

【讨论】:

    【解决方案2】:

    我能想到的唯一解释是您将标签堆叠在同一行和同一列中,因此当您添加一个以“nce ...”结尾的长字符串并稍后更新屏幕时通过在同一个网格单元格中添加一个较短的标签,下面较长标签的尾随文本会显示出来。

    我得出这个结论的原因是:

    1. 这是我见过多次的常见错误
    2. tkinter 中没有会导致此问题的错误
    3. 您展示的代码中没有任何内容可以在字符串末尾添加“nce...”
    4. 您使用 sticky="w" 而不是 sticky="ew" 的事实,如果将较短的标签放置在同一行和同一列中,这将导致较短的标签无法完全覆盖较长的标签

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-08-01
      • 1970-01-01
      • 2015-05-24
      • 1970-01-01
      • 2017-04-12
      • 1970-01-01
      相关资源
      最近更新 更多