0

I want to use the tkinter to build a GUI to control the python script.

The code looks like,

kansai = Page(kansai_url)
tokyo = Page(tokyo_url)

def loop_main():

    with concurrent.futures.ProcessPoolExecutor() as executor:
        k = executor.submit(kansai.compare)
        t = executor.submit(tokyo.compare)

    kansai_lbl['text'] = k.result()
    tokyo_lbl['text'] = t.result()

    root.after(60000, loop_main)


if __name__ == '__main__':

    root = tk.Tk()

    # --buttons--
    start_btn = tk.Button(root, text='Start', command=loop_main, font='Raleway', bg='#20bebe', fg='white', height=2,
                          width=10)
    start_btn.grid(column=1, row=3)

    refresh_btn = tk.Button(root, text='Refresh', font='Raleway', bg='#20bebe', fg='white', height=2, width=10)
    refresh_btn.grid(column=2, row=3)

    quit_btn = tk.Button(root, text='Quit', command=root.destroy, font='Raleway', bg='#20bebe', fg='white', height=2,
                         width=10)
    quit_btn.grid(column=3, row=3)

    # -- instruction --
    kansai_name_lbl = tk.Label(root, text='Kansai', font='Raleway')
    kansai_name_lbl.grid(column=1, row=0)
    tokyo_name_lbl = tk.Label(root, text='Tokyo', font='Raleway')
    tokyo_name_lbl.grid(column=3, row=0)

    kansai_lbl = tk.Label(root)
    kansai_lbl.grid(column=1, row=1)

    tokyo_lbl = tk.Label(root)
    tokyo_lbl.grid(column=3, row=1)

    root.mainloop()

My goal is that, I want to control the running of the script via the start and stop buttons. The script is written as the loop_main running with multiprocessing, takes about 20secs to finish.

My problem is when I click start, the script started but the GUI just went no responding and I can't click the quit button. Only during the interval of running, I can click the buttons. But I want to exit the script via quit button at any time.

How can I fix this?

martineau
  • 119,623
  • 25
  • 170
  • 301
Leo_Liu
  • 37
  • 5
  • I think the calls to `result()` are taking a long time to execute which interferes with the running of tkinter's own `mainloop()` and will make the GUI "freeze" until they both return. You can fix it by using `add_done_callback()` and not waiting for each process to finish. – martineau Sep 02 '21 at 10:23
  • Another possibility would be to control the processes in another thread that doesn't use tkinter (which is not thread-safe). This will require the GUI thread to periodically check for results from the process-control thread using something like a `Queue`. See the answer I posted to the question [Freezing/Hanging tkinter GUI in waiting for the thread to complete](https://stackoverflow.com/questions/53696888/freezing-hanging-tkinter-gui-in-waiting-for-the-thread-to-complete) for an example. – martineau Sep 02 '21 at 10:38

1 Answers1

1

I had an issue with tkinter gui becoming unresponsive while application was executing a function. For me the solution was "threading":

import tkinter
import time
from threading import Thread


def start():
    def something_slow():
        global stop
        stop = False
        while not stop:
            print("doing stuff")
            time.sleep(1)
        print("stoped doing stuff")
    executing = Thread(target=something_slow)
    executing.start()


def stop():
    global stop
    stop = True


main_window_of_gui = tkinter.Tk()
button_start = tkinter.Button(main_window_of_gui, text="Start", command=start)
button_start.grid(row=0, column=0)

button_stop = tkinter.Button(main_window_of_gui, text="Stop", command=stop)
button_stop.grid(row=0, column=1)

main_window_of_gui.mainloop()
stop = True
Mikhail Ilin
  • 186
  • 1
  • 7
  • 1
    Just as a small note: Don't call `tkinter` method from threads other than the one where you created the `tk.Tk`. It can cause a log of issues that are nearly impossible to debug. – TheLizzard Sep 02 '21 at 11:15
  • 1
    Running this code actually works. But one problem is that after I closed the interface, the script still kept running. – Leo_Liu Sep 02 '21 at 12:08
  • @Leo_Liu Good point! I've added "stop = True" at the end, so when the interface is closed, the thread loop can be stopped. – Mikhail Ilin Sep 03 '21 at 08:52