Home > Software design >  Can you call mainloop() more than once in tkinter?
Can you call mainloop() more than once in tkinter?

Time:06-16

What I mean by this is can you make the program open the window more than once by putting the mainloop() function in a for loop or a while loop? It would probably look something like this:

for i in range(n):
  window.mainloop()

Or this if we are using a while loop:

i = 0
while i < n:
  window.mainloop()

When I try either of these methods, it just opens one window. Am I doing something wrong or is mainloop() a function that cannot be put in a loop? If that is the case, is there any other method?

CodePudding user response:

Calling mainloop more than once can't open new windows. mainloop only processes events, it doesn't create or recreate any windows.

If you need multiple windows, the way to do that is to create instances of Toplevel for the second and subsequent windows. You then call mainloop exactly once and all of the windows will be visible assuming they've been set up to be visible.

If you want to create multiple instances of the same window, the normal pattern is to create your app in a class that inherits from Frame. You can then create as many windows as you want, and in each one you can create an instance of that frame.

Here is an example of the technique:

import tkinter as tk


class App(tk.Frame):
    def __init__(self, parent, *args, **kwargs):
        super().__init__(parent, *args, **kwargs)
        self.count = 0
        self.button = tk.Button(self, text="Click me!", command=self.click)
        self.label = tk.Label(self, text="", width=20)

        self.label.pack(side="top", fill="both", expand=True)
        self.button.pack(side="bottom", padx=4, pady=4)

        self.refresh_clicks()

    def click(self):
        self.count  = 1
        self.refresh_clicks()

    def refresh_clicks(self):
        self.label.configure(text=f"Clicks: {self.count}")

apps = []
n = 5
for i in range(n):
    window = tk.Tk() if i == 0 else tk.Toplevel()

    app = App(window)
    app.pack(fill="both", expand=True)
    apps.append(app)

tk.mainloop()

It's important to note that if you delete the very first window, all of the other windows will be deleted. If you don't want that to happen, you can create and then hide the root window so that the user can only see the other windows. You'll then need to add some code to kill the root window when there are no longer any child windows.

CodePudding user response:

You can run each one in a new thread or process, but probably a better way within tkinter is to run multiple windows within one main loop.

I'll try to edit this later with code examples of how to do that.

As for why it doesn't work:

window.mainloop is a blocking/ongoing operation - it kinda hints at this by having "loop" in the name - inside that function is what's called an "event loop", and the code just sits in that loop waiting for and handling window events until the window is closed.

You can think of it almost like this:

def mainloop():
    while window_exists:
        ...
        # this is why it doesn't work
        # it loops forever in here

for i in range(n):
    mainloop()

For more detail, you can dive into the tkinter documentation where you'll find similar explanations:

Tcl/Tk applications are normally event-driven, meaning that after initialization, the interpreter runs an event loop [...] This is different from many GUI toolkits where the GUI runs in a completely separate thread from all application code including event handlers.

  • Related