Home > Enterprise >  How to wait for a server response without freezing the tkinter GUI
How to wait for a server response without freezing the tkinter GUI

Time:09-08

I am making a tkinter GUI that requests information to a server that takes some time to respond. I really don't know how to tell tkinter to wait for the response in a clever way so that the window loop doesnt freeze.

What I want to achieve is to make the popup window responsive, and to see the animation of the progressbar. I don't really know if it helps but I intend to use this GUI on Windows.

Here is my code: (I used time.sleep to simulate sending and recieving from a server)

import tkinter as tk
import tkinter.ttk as ttk
import time


def send_request(data):
    # Sends request to server, manages response and returns it
    time.sleep(10)


class Window(tk.Toplevel):
    def __init__(self, root, *args, **kargs):
        super().__init__(root, *args, **kargs)
        # Options of the window
        self.geometry("500x250")
        self.resizable(False, False)
        self.grab_set()
        # Widgets of the window
        self.button = tk.Button(self, text="Send Request", command=self.start_calc)
        self.button.pack()
        self.bar = ttk.Progressbar(self, orient = "horizontal", mode= "indeterminate")
        self.bar.pack(expand=1, fill=tk.X)

    def start_calc(self):
        # Prepares some data to be send
        self.data_to_send = []
        # Start bar
        self.bar.start()
        # Call send request
        self.after(10, self.send_request_and_save_results)

    def send_request_and_save_results(self):
        # Send request with the data_to_send
        result = send_request(self.data_to_send)
        # Save results
        # Close window
        self.quit()
        self.destroy()


class App:
    def __init__(self, root):
        self.root = root
        self.button = tk.Button(root, text="Open Window", command=self.open_window)
        self.button.pack()

    def open_window(self):
        window = Window(self.root)
        window.mainloop()


root = tk.Tk()
root.geometry("600x300")
app = App(root)
root.mainloop()

CodePudding user response:

Use threading module to run your code and get the request parallelly

Just call your function like this.

t1 = Thread(target=window.send_request_and_save_results)
t1.start()

Updated Code

import tkinter as tk
import tkinter.ttk as ttk
import time
from threading import Thread

def send_request(data):
    # Sends request to server, manages response and returns it
    time.sleep(10)


class Window(tk.Toplevel):
    def __init__(self, root, *args, **kargs):
        super().__init__(root, *args, **kargs)
        # Options of the window
        self.geometry("500x250")
        self.resizable(False, False)
        self.grab_set()
        # Widgets of the window
        self.button = tk.Button(self, text="Send Request", command=self.start_calc)
        self.button.pack()
        self.bar = ttk.Progressbar(self, orient = "horizontal", mode= "indeterminate")
        self.bar.pack(expand=1, fill=tk.X)

    def start_calc(self):
        # Prepares some data to be send
        self.data_to_send = []
        # Start bar
        self.bar.start()
        # Call send request
        self.after(10, self.send_request_and_save_results)

    def send_request_and_save_results(self):
        # Send request with the data_to_send
        result = send_request(self.data_to_send)
        # Save results
        # Close window
        self.quit()
        self.destroy()


class App:
    def __init__(self, root):
        self.root = root
        self.button = tk.Button(root, text="Open Window", command=self.open_window)
        self.button.pack()

    def open_window(self):
        window = Window(self.root)
        t1 = Thread(target=window.send_request_and_save_results)
        t1.start()
        window.mainloop()


root = tk.Tk()
root.geometry("600x300")
app = App(root)


root.mainloop()


I hope this will help you.

CodePudding user response:

Thanks to @codester_09 suggestion of using threading.Thread I have managed to get it working but I don't really understand why. After many errors this is what I did.

Now I wonder if what I did is safe.

import tkinter as tk
import tkinter.ttk as ttk
import time
from threading import Thread


def send_request_and_save_results(data):
    global results
    print("Start sending: ", data)
    # Sends request to server, manages response and returns it
    time.sleep(10)
    print("Finished sending")
    # Save results
    results[0] = "Hello"
    results[1] = "Hola"


class Window(tk.Toplevel):
    def __init__(self, root, *args, **kargs):
        super().__init__(root, *args, **kargs)
        # Options of the window
        self.geometry("500x250")
        self.resizable(False, False)
        self.grab_set()
        # Widgets of the window
        self.button = tk.Button(self, text="Send Request", command=self.start_calc)
        self.button.pack()
        self.bar = ttk.Progressbar(self, orient = "horizontal", mode= "indeterminate")
        self.bar.pack(expand=1, fill=tk.X)

    def start_calc(self):
        # Prepares some data to be send
        self.data_to_send = [1, 2, 3]
        # Start bar
        self.bar.start()
        # Call send request
        t1 = Thread(target=self.send_request_and_save_results)
        self.after(10, t1.start)

    def send_request_and_save_results(self):
        # Send request with the data_to_send
        send_request_and_save_results(self.data_to_send)
        # Close window
        self.after(10, self.close)

    def close(self):
        self.quit()
        self.destroy()


class App:
    def __init__(self, root):
        self.root = root
        self.button = tk.Button(root, text="Open Window", command=self.open_window)
        self.button.pack()

    def open_window(self):
        window = Window(self.root)
        window.mainloop()

#
root = tk.Tk()
root.geometry("600x300")
app = App(root)
results = [None] * 10
root.mainloop()
  • Related