Search code examples
pythonpython-3.xmultithreadingtkintertkinter-entry

Strange behavior using Tkinter Entry.get() with threads


I'm been facing some strange issues trying to get tkinter (particularly the Entry class) to work with threads. I've narrowed the problem to the following sample:

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

For some reason self.field.get() returns each digit in the entry field separately; I needed *args in getField() to discover this. When you press the button, the following is printed:

2
0
0

I expected .get() to return the whole field entry. Strangely, .get() also does not respond to new field entries, changing the value in the UI results in the same output.

The following code without threads works perfectly:

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

What's wrong with my threaded code?


Solution

  • Below code got it working for me:

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

    It solved both problems - it shows the number in one line, because you only call the self.field.get() in the getField function, instead of as an arg. And it also shows me correct value even if I change the value, which did not work for me with the code you posted.