15

I developed a simple Python application doing some stuff, then I decided to add a simple GUI using Tkinter.

The problem is that, while the main function is doing its stuff, the window freezes.

I know it's a common problem and I've already read that I should use multithreads (very complicated, because the function updates the GUI too) or divide my code in different function, each one working for a little time. Anyway I don't want to change my code for such a stupid application.

My question is: is it possible there's no easy way to update my Tkinter window every second? I just want to apply the KISS rule!

I'll give you a pseudo code example below that I tried but didn't work:

    class Gui:
        [...]#costructor and other stuff

        def refresh(self):
            self.root.update()
            self.root.after(1000,self.refresh)

        def start(self):
            self.refresh()
            doingALotOfStuff()

    #outside
    GUI = Gui(Tk())
    GUI.mainloop()

It simply will execute refresh only once, and I cannot understand why.

Thanks a lot for your help.

decadenza
  • 2,380
  • 3
  • 18
  • 31
  • You can't expect your program to run `self.refresh` every second while it's busy `doingALotOfStuff()`. I don't think you'll get around multithreading. – Aran-Fey Feb 23 '17 at 17:17
  • I got it. It appears just crazy to me there's no easy solution to do such a simple software... Maybe someone will show us any trick! – decadenza Feb 25 '17 at 00:00

3 Answers3

23

Tkinter is in a mainloop. Which basically means it's constantly refreshing the window, waiting for buttons to be clicked, words to be typed, running callbacks, etc. When you run some code on the same thread that mainloop is on, then nothing else is going to perform on the mainloop until that section of code is done. A very simple workaround is spawning a long running process onto a separate thread. This will still be able to communicate with Tkinter and update it's GUI (for the most part).

Here's a simple example that doesn't drastically modify your psuedo code:

import threading

class Gui:
    [...]#costructor and other stuff

    def refresh(self):
        self.root.update()
        self.root.after(1000,self.refresh)

    def start(self):
        self.refresh()
        threading.Thread(target=doingALotOfStuff).start()

#outside
GUI = Gui(Tk())
GUI.mainloop()

This answer goes into some detail on mainloop and how it blocks your code.

Here's another approach that goes over starting the GUI on it's own thread and then running different code after.

Community
  • 1
  • 1
double_j
  • 1,636
  • 1
  • 18
  • 27
  • 2
    Thank you, I appreciate your help. I think that the main problem is due to the fact that the function doingALotOfStull() is indeed updating the GUI too... I guess there's no smart solution here. I have to study multithreading or, eventually, avoid the GUI at all... – decadenza Feb 24 '17 at 23:57
  • If I start that thread, Tk never starts running. If I try to start that thread after Tk, the thread never starts running... – SJ10 Jan 25 '22 at 04:39
3

'Not responding' problem can be avoided using Multithreading in python using the thread module.

If you've defined any function, say combine() due to which the Tkinter window is freezing, then make another function to start combine() in background as shown below:

import threading
def combine():
    ...

def start_combine_in_bg():
    threading.Thread(target=combine).start()

Now instead of calling combine(), you have to call start_combine_in_bg() I did this and now my window is not freezing so I shared it here. Remember you can run only one thread at a time.

Have a look for reference: stackoverflow - avoid freezing of tkinter window using one line multithreading code

Prashantzz
  • 301
  • 2
  • 7
1

Here's how I managed to work around this issue (maybe it's quite dirty I don't know):

Whenever I update my tkinter window through the doingALotOfStuff() function, I call myTk.update().

It avoids freezing for me.

Jurgen Strydom
  • 3,540
  • 1
  • 23
  • 30
elray
  • 11
  • 1