Michal
Michal

Reputation: 1320

Multiple application/file/windows instances running on tkinter

Here is a sample situation:

I have written a tk GUI that opens and edits e.g. .txt files. I'm currently on a mac, but I might also want to run this on windows. Currently the main Application class creates its own internal tk.Tk() like so

    import tkinter as tk

class App:
    def __init__(self):
        self.root = tk.Tk()
        tk.Label(master=self.root,text="content").pack()

if __name__ == '__main__':
    a=App()
    a.root.mainloop()

I want to add multi file capabilities to the application. In the current system this would result in 2 tk.Tk() instances running which I couldn't get to work and people say is unpredictable.

I want to be able to close any of the multiple files and still have the application running until the last window is closed and then the application quit or stays without a window (like on a mac).

My problem is that if I use tk.Toplevel() for each of my windows I have a ugly default tk.Tk() window which I would need to hide which seams inelegant. It would also be messy to determine which file is currently in focus for actions with the menubar.

I'm also considering each file being it's own application instance like on Windows, but that would fill the dock with repeated icons and be inconsistent with the rest of the system.

Here are the possible way I came up with: Multiple Tks (Works but more complex examples are unpredictable):

import tkinter as tk

class App:
    def __init__(self):
        self.root = tk.Tk()
        tk.Label(master=self.root,text="content").pack()
        tk.Button(master=self.root,text="new_window",command=self.open).pack()

    def open(self):
        App()

if __name__ == '__main__':
    a=App()
    a.root.mainloop()

Hidden tk window and multiple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):

import tkinter as tk

class App:
    def __init__(self):
        self.root = tk.Toplevel()
        tk.Label(master=self.root,text="content").pack()
        tk.Button(master=self.root,text="new_window",command=self.open).pack()

    def open(self):
        App()

if __name__ == '__main__':
    tk.Tk()
    a=App()
    a.root.mainloop()

Each Window is its own Application and fully independant (Dosn't fit in with the other mac applications, the implementation is ugly):

#!/usr/local/bin/python3
import tkinter as tk
import sys,os

class App:
    def __init__(self):
        self.root = tk.Tk()
        tk.Label(master=self.root,text="content").pack()
        tk.Button(master=self.root,text="new_window",command=self.open).pack()

    def open(self):
        os.system(sys.argv[0]+"&")

if __name__ == '__main__':
    a=App()
    a.root.mainloop()

I was alos think of maybe doing it with threads but I think I must be over thinking it so I came here. Is there a generally accepted way of doing this in tk?

Upvotes: 1

Views: 1544

Answers (2)

user4171906
user4171906

Reputation:

Hidden tk window and multyple Toplevels (Needs hiding the Tk and the osx menubar commands like view->change_colors would need to manaly decide where to direct comands):

It is easy to get into "which goes with what" hell with multiple Toplevels. Instead create a separate class for each new Toplevel with built in responses to button clicks, etc. Pass "root" to the class and let it create, update, and destroy as necessary, and keep track of it's own variables. If you want to use variables elsewhere, then store the class instance when the Toplevel classes are called and create the variables within the class as instance attributes.

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 386240

The generally accepted way is just like you describe: use Toplevel for additional windows, and hide the root window if you don't want to see it.

Another choice is to make your main program a non-GYI app, and each window is created by spawning a new process.

Upvotes: 4

Related Questions