1

My understanding of tk.mainloop() was that it would run and handle the events of window related to the first created Tcl interpreter and <widget>.mainloop() would handle the events of the window related to the interpreter linked with the widget. Then I came across this code:

from tkinter import *

root1 = Tk()
root2 = Tk()

root1.mainloop() # Shouldn't this just handle the events of the first window

According to my understanding I thought this code was supposed to handle just the events related to root1, but root2 also comes up and it is responsive too(which means that its events are also being processed..?). Do correct me if my understanding of how mainloop() works is wrong.

Thanks :D

Delrius Euphoria
  • 14,910
  • 3
  • 15
  • 46
  • Basically you only need 1 `.mainloop()` in your code because it handles the events from all windows. Also look at the documentation, `.mainloop()` actually takes in 1 parameter, the number of `Tk()` windows left before the function returns. The default is 0. – TheLizzard Aug 15 '21 at 14:43
  • @TheLizzard In that question the 2nd `mainloop()` is also called, but here it is not called. – Delrius Euphoria Aug 15 '21 at 14:47
  • Replacing `.mainloop()` with `while True: root1.tk.dooneevent(_tkinter.DONT_WAIT)`, still has the same effect. Therefore, the question is actually about how `tcl` handles multiple `tcl` interpreters. – TheLizzard Aug 15 '21 at 15:25
  • [This](http://aejaks.sourceforge.net/Documentation/jacl1.4.0/Topics/EventLoop.html#:~:text=Multiple%20Interpreters) says that you can have multiple tcl interpreters linked to 1 event queue. – TheLizzard Aug 15 '21 at 15:36
  • @TheLizzard Hmmm I see. So `Notifier` is something like `mainloop`? – Delrius Euphoria Aug 15 '21 at 17:47
  • 1
    I think the `Notifier` is just the event queue but it also handles `after` scripts. I might be misunderstanding that webpage. I think we should put the [tag:tcl] tag. But I don't know much about this topic. – TheLizzard Aug 15 '21 at 17:56

1 Answers1

1

The mainloop() method runs the event processing loop on the current thread until all windows started in the thread have closed or the quit() method is called (which internally sets a flag that is checked by the core event loop runner). It blocks the thread, except that it does all the registered callbacks as necessary. The underlying machinery is not actually associated with any particular window, but rather with a thread. It's just that Tkinter prefers to not map things as free functions, despite that really being what they are.

You're pretty strongly recommended to not have the results of two calls to tkinter.Tk() active at once. It works, but the result can be quite confusing. It can get even more confusing if you do it from several threads at once (which is supposed to work — except on macOS for messy reasons — but the results tend to be mind-bending). (This does not apply to tkinter.Tcl(); that does work reasonably when done multiple times, and from multiple threads. The object it produces is thread-bound, but having many instances is sensible, and you can have those instances either in their own threads or together.)


What doing two calls to tkinter.Tk() like you've done does is create two separate underlying Tcl/Tk environments (the technical term is an “interpreter” even though that's got a bytecode compiler and so on) sharing a thread. This is sensible from a Tcl/Tk perspective due to the very different security model that Tcl uses, but it's almost total nonsense from the view of Python. The effects are describable small-scale operationally, but making broader sense of them is very difficult, and you're advised to not try.

Donal Fellows
  • 133,037
  • 18
  • 149
  • 215
  • OH okay, so then what is the difference between `tk.mainloop()` and `widget.mainloop()`? They would behave the same way here – Delrius Euphoria Aug 15 '21 at 19:48
  • What makes me curious about your answer is that you can call the `quit` method on every window and the thread ends, at least it seems so and the windows are still responsible. So I think there needs to be difference between what runs in the IDE and in the OS shell. – Thingamabobs Aug 15 '21 at 21:28
  • There's no difference between them; `widget.mainloop()` is just an alias for `tk.mainloop()` and wouldn't have ever been made if I'd written Tkinter. – Donal Fellows Aug 16 '21 at 11:11
  • So [this](https://stackoverflow.com/a/51428450/13382000) answer is technically wrong? – Delrius Euphoria Aug 16 '21 at 11:17
  • 1
    Bryan's a bit confused in that answer. The code doesn't use the _first_ one, but rather uses the ones that the event handlers are registered to (this is a definitely known thing) and finds them on the _current_ thread. If you've got Tkinter window stacks in several threads (*not recommended!*) then each of those threads needs its own main loop. – Donal Fellows Aug 16 '21 at 15:49
  • 1
    At the low level, each time you call `tkinter.Tk()` you get a new connection to the system event source (the X server, or the system message pump on Windows). That's then slotted into the per-thread notifier engine — a chunk of C code that knows how to wait for events efficiently — which powers the guts of `mainloop()`. There's a lot of other detail, but that's the heart of it. – Donal Fellows Aug 16 '21 at 15:55