1

3 sub questions:
[1] python GUIs are polling based?
it seems to me that both tk and qtpy are polling based, if the gui calls a function that takes a while to excecute, the entire gui hangs.
I learnt about gui long time ago, I remembered that modern gui should be interrupt based, even when gui were executing something big, gui should be responsive all the time. gui may not display the result from those big calculations, but it will respond to resize, show button click animation etc. So my question is, Is there an option like:

    #psuedo code
    root=tkinter.Tk()
    root.setInterruptMode(True)

[2] Is tk.mainloop() just a gigantic loop?
if my first question is a pipe dream, and I will just have to learn about threading and multiprocess, then my next question is about root.mainloop() (or qtpy's exec_()).
My impression is that mainloop() doesn't really start a thread or anything in python, it just packs a gigantic and invisible tkinter's gui polling+painting loop into my main line. Is my impression correct?

[3] why putting mainloop in Main line?
Does mainloop() have to reside in the Main line? can I thread/multiprocess it out? so that my Main line can concentrate on big calculations, and the Main line governs gui process and IO processes. All the examples I came across have mainloop() in the Main line, I am not sure it is a recommended approach or what the benefits are.

Below is the code I wrote while trying to learn about python gui:

    import tkinter
    import random

    class myGUI():
        def __init__(self, arg_tkroot):
            self.GUI_display = tkinter.Label(arg_tkroot, text='init-ed')
            self.GUI_button = tkinter.Button(arg_tkroot, text='click')
            self.GUI_display.pack()
            self.GUI_button.pack()

            self.GUI_button.bind('<Button-1>', self.handle_user_interaction)
            self.list_bigData = []

        #handles GUI interaction, and call bigData_and_bigCalculation()
        def handle_user_interaction(self, arg_event):
            print(arg_event, ' detected by myGUI')
            strResult_toFeedbackToUser = self.bigData_and_bigCalculation()
            self.GUI_display.config(text=strResult_toFeedbackToUser)
            print('finished handling user interact')

        # slow calculations and memory consuming operations
        def bigData_and_bigCalculation(self):
            self.list_bigData[:]=[]
            for i in range(500000):
                self.list_bigData.append( ''.join(random.choice('asdfas') for k in range(10)) )
            return self.list_bigData[-1]
    # Main()
    if __name__ == '__main__':
        root = tkinter.Tk()
        mygui = myGUI(root)
        root.mainloop()
YunliuStorage
  • 479
  • 5
  • 14
  • 1
    Well, if you'll execute some long job in the GUI thread, then the GUI will freeze. To avoid this, spawn different threads for different jobs. – ForceBru Apr 15 '16 at 18:11
  • interesting question; I have written about 10 small and one average size app in Tk (none in Qt) never had responsiveness isues and never thought of a way Tk does it's GUI :) I suggest following ForceBru adwise in general; and by the way I have moved to use Kivy for my GUI apps, can recommend, it's more flexible than Tk and works nicely on android and ios as well if needed. – Drako Apr 15 '16 at 18:18
  • I was afraid having to use threading and multiprocess is inevitable. But in my first sub question, what I learnt before about "interrupt" based gui (java applet back then), I never ecountered gui freeze back then, that was an wrong impression because we never did any big calculations while learning those things? – YunliuStorage Apr 15 '16 at 18:36
  • If you can break a 1+ second job into, say 10 or even 100 millisecond pieces, then you can loop with root.after and intersperse pieces of the job with responses to other events. Search SO for `[tkinter] root.after` for examples. – Terry Jan Reedy Apr 16 '16 at 00:26

1 Answers1

2

[1] GUIs are polling based?

GUIs are event based -- everything that happens in a GUI is a response to an event. How the application handles the event is up to the application. If the handling of the event can happen in a few hundred milliseconds or less it can be handled in the main thread. If it is going to take longer, the application should run the code in a separate thread or process.

In the case of Tkinter, Tkinter is designed to run in a single thread. That doesn't mean you can't use threads, only that all access to tkinter objects should be on a single thread. The common way to do this is for other threads to communicate with the GUI via a thread-safe queue, and the GUI thread is responsible for checking that queue periodically.

So my question is, Is there an option like [root.setInterruptMode(True)]

In tkinter, no, there is no way to enter a special "interrupt" mode.

[2] It is just a gigantic loop?

I assume by "it" you mean the call to mainloop. Yes, it's a gigantic loop. Or perhaps more correctly, it's a tiny loop. All it does is wait for an event, then it looks up the handler for the event and runs the handler.

My impression is that mainloop() doesn't really start a thread or anything in python

Correct. It runs the event loop in the current thread.

[3] why putting mainloop in Main line?

You would have to ask the original developers that. Likely it's because that's all that is necessary for a very, very large percentage of applications (perhaps more true back when the toolkit was invented than it is now).

Tkinter is nothing but a wrapper around a tcl interpreter with the tk toolkit loaded in the interpreter. tcl/tk was designed to be embedded in other applications, so it needed to be lightweight, and be able to run on systems that don't support threads (tcl is old enough that thread support wasn't guaranteed on every platform)

Does mainloop() have to reside in the Main line? can I thread/multiprocess it out?

mainloop() needs to be run in the same thread that created the root window. If you need threads (and again, it's quite possible that you don't), you can certainly run your event handlers in a separate thread. It adds complexity, but it's there if you need it. For a large class of programs, there's simply no need for that much complexity.

You should be able to create a worker thread and create and run your GUI from there. I've never tried it, but I see no reason why it wouldn't work. Tkinter doesn't care that it's the main thread, only that all tkinter code runs in the same thread.

All the examples I came across have mainloop() in the Main line, I am not sure it is a recommended approach or what the benefits are.

Calling mainloop in the main thread is how tkinter was designed to work. If you have long running calculations, you should put those calculations in a separate thread or process.

Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
  • Thank you for the step by step answer, I will definitely need threads or processes, I have too many IOs and Obscene amount of big data structures. What interests me is that, in your previous answer to a similar question, quoted by other helpers here, you mentioned tk being not suitable running in thread mode; but you seem to be saying now, it is ok to do it. – YunliuStorage Apr 15 '16 at 19:43