Search code examples
pythonuser-interfacetkinterthreadpoolconcurrent.futures

Global/Local namespace issue while updating Tkinter GUI in Python2.7?


EDIT: I have built a User Interface using Tkinter in Python 2.7 and I am also receiving data at the socket with concurrent.futures module. Now I want GUI to update whenever there's a new data at sock.recv() but that is not happening, may be because the global 'val1' is updating in one future thread (that's handling sockets) but not the other thread which is handling the GUI. So the Listbox in GUI containing val1 remains static. It is a very long code so instead of putting the whole code here I'm just adding a pseudo-code to clarify the issue.

from Tkinter import *
import concurrent.futures
....

class UserInterface(Frame):
    def __init__(self, root):
        Frame.__init__(self, root)
        self.root = root

        global var1, var2

        # Rest of the code

        self.update()
        root.mainloop() # I have to do this, otherwise the GUI doesn't show


    def update(self):
        try:
            self.var1 = var1
            self.var2 = var2

            # Inserting/displaying the latest values of var1 and var2 in Listbox defined in the constructor
            # Rest of the update function

            self.root.after(5000, update)
        except:
            pass


def conn_handler(conn, addr):
    global val1, val2
    while True:
        buff= conn.recv(2048)
        data= json.loads(buff.strip('x'))    # 'x' is the EOL character
        val1 = ''.join(data[key1]) # not exactly but something like this
        val2 = ''.join(data[key2]) # and so on

def ui_handler():
    root= Tk()
    my_gui = UserInterface(root)
    # I earlier put my_gui.root.mainloop() here but that doesn't help either


def main():
    with concurrent.futures.ThreadPoolExecutor(5) as executor:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

        sock.bind((HOST, PORT))
        while True:
            sock.listen(5)
            conn, addr = sock.accept()
            future1 = executor.submit(conn_handler, conn, addr)
            future2 = executor.submit(ui_handler)
            concurrent.futures.wait([future1, future2])


if __name__=='__main__':
    val1 = {'key1':value1, 'key2':value2, 'key3':value3, 'key4':value4, 'key5':value5}
    val2 = {'key1':value1, 'key2':value2, 'key3':value3, 'key4':value4}
    main()

There is no error in the code when I run it, but it is not doing what I want to be done, that is, to update the GUI every time there is a new data at the receiving socket. Is there some fault in my approach/logic ?

P.S. I'm quite new to Python and programming in general, so please be kind!


Solution

  • It might not be the issue of local or global namespaces; it may as well be a simple issue of text box or list box not refreshing. I suggest in every update function, you once delete the earlier values inside the widget and then insert anything new!

    In your case, something like this:

    self.list_box.delete(0, END)
    for i in range(len(values)):
        self.list_box.insert(END, values[i])