【问题标题】:Strange behavior using Tkinter Entry.get() with threads使用带有线程的 Tkinter Entry.get() 的奇怪行为
【发布时间】:2020-09-08 09:22:38
【问题描述】:

我在尝试让 tkinter(尤其是 Entry 类)使用线程时遇到了一些奇怪的问题。我已将问题范围缩小到以下示例:

from threading import Thread
from tkinter import *

class App:
    def __init__(self):
        
        self.root = Tk()
        self.field = Entry(self.root)
        self.field.insert(0,200)

        self.but = Button(text = 'get', command = Thread(target = self.getField,
                                                        args = self.field.get()
                                                        ).start)

        self.field.pack()
        self.but.pack()

    def getField(self, *args):
        for arg in args:
            print (arg)
        return

myApp = App()
myApp.root.mainloop()

出于某种原因self.field.get() 分别返回输入字段中的每个数字;我需要getField() 中的*args 来发现这一点。当您按下按钮时,将打印以下内容:

2
0
0

我希望 .get() 返回整个字段条目。奇怪的是,.get() 也不会响应新的字段条目,更改 UI 中的值会导致相同的输出。

以下没有线程的代码完美运行:

from threading import Thread
from tkinter import *

class App:
    def __init__(self):
        
        self.root = Tk()
        self.field = Entry(self.root)
        self.field.insert(0,200)

        self.but = Button(text = 'get', command = self.getField)

        self.field.pack()
        self.but.pack()

    def getField(self, *args):
        print(self.field.get())
        return

myApp = App()
myApp.root.mainloop()

我的线程代码有什么问题?

【问题讨论】:

    标签: python python-3.x multithreading tkinter tkinter-entry


    【解决方案1】:

    下面的代码让它为我工作:

    from threading import Thread
    from tkinter import *
    
    class App:
        def __init__(self):
            
            self.root = Tk()
            self.field = Entry(self.root)
            self.field.insert(0,200)
            self.field.pack()
            self.but = Button(text = 'get', command = self.threadGetField) 
            self.but.pack()
            self.root.mainloop()
    
        def threadGetField(self):
            my_thread = Thread(target=self.getField())
            my_thread.start()
    
        def getField(self):
            print(self.field.get())
            return
    
    myApp = App()
    

    它解决了这两个问题 - 它在一行中显示数字,因为您只在 getField 函数中调用 self.field.get(),而不是作为 arg。即使我更改了值,它也会向我显示正确的值,这对您发布的代码不起作用。

    【讨论】:

    • 感谢您的回答。确实有效,但我很好奇为什么在args 参数中嵌入.get() 方法会导致打印旧值?我怀疑它在App 初始化后立即运行.get(),但这没有意义,因为线程只有在您按下按钮时才会启动。
    • @Darrel:这是因为对 get() 的调用是在按钮创建时发生的,而不是在单击时发生的。
    【解决方案2】:

    Thread 的参数应作为元组传递,如文档中所述:args 是目标调用的参数元组...
    用它的唯一项目创建一个元组是self.field.get() 使您的代码工作:

    from threading import Thread
    from tkinter import *
    
    class App:
        def __init__(self):
            
            self.root = Tk()
            self.field = Entry(self.root)
            self.field.insert(0,200)
    
            self.but = Button(text = 'get', command = Thread(target = self.getField,
                                                            args = (self.field.get(), )
                                                            ).start)
    
            self.field.pack()
            self.but.pack()
    
        def getField(self, *args):
            print('>>>', args)
            for arg in args:
                print (arg)
            return
    
    myApp = App()
    myApp.root.mainloop()
    

    输出:

    ('>>>', ('200',))
    200
    

    【讨论】:

    • 感谢您的回答。您的解决方案将返回解析为单独的数字,但输出仍然忽略该字段的任何新输入。尝试在 UI 中将数字更改为 999,它仍然输出 200。
    • 这在真正的应用程序中不起作用,因为您在创建条目小部件大约一毫秒后调用self.fields.get()。线程将始终只有初始值,而不是用户输入的值。
    猜你喜欢
    • 1970-01-01
    • 2013-02-15
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-27
    • 1970-01-01
    相关资源
    最近更新 更多