0

I want to create independent window. each create window, when caller window close or destroy. so far is create window without problem. but console warning message that i dont know what is this.

Console warning

can't invoke "event" command: application has been destroyed while executing "event generate $w <>" (procedure "ttk::ThemeChanged" line 6) invoked from within "ttk::ThemeChanged"

import tkinter

class MainWindow(tkinter.Tk):
    def __init__(self, condition):
        super().__init__()

        self.title("Main Window ")
        self.geometry("640x360")

        if (condition == 1):
            DashboardWindow() 
            self.destroy()
            

class DashboardWindow(tkinter.Tk):
    def __init__(self):
        super().__init__()

        self.title("Dashboard Window")
        self.geometry("940x560")

    
    
MainWindow(1).mainloop()
david stephen
  • 329
  • 4
  • 12
  • `tk.Tk()` is considered as the root of your application and to code with 2 root windows is a complete mess. Rather you could write 2 programs and run a program where those are running simultaneously. – Thingamabobs Sep 05 '21 at 07:02
  • See [Why are multiple instances of Tk discouraged?](https://stackoverflow.com/questions/48045401/why-are-multiple-instances-of-tk-discouraged) – martineau Sep 05 '21 at 07:17
  • @Atlas435 No it's not a complete mess. Right now OP is calling `self.destroy()` and then trying to call `.mainloop()`. That will obviously crash the program as the `tk.Tk` window no longer exists. – TheLizzard Sep 05 '21 at 08:46
  • @TheLizzard I thought the destroy method is just called to demonstrate what OP is trying to achive. Otherwise the title of this question is missleading. *How to create window independent each other?* – Thingamabobs Sep 05 '21 at 09:03
  • @Atlas435 OP is trying to create windows independent of each other but accidentally calls `.mainloop()` after `.destroy()`. And to create windows that are independent of each other, you need to use multiple instances of `tk.Tk()`. – TheLizzard Sep 05 '21 at 09:05
  • @TheLizzard I can see how you interpret the question. No need to explain. – Thingamabobs Sep 05 '21 at 09:08
  • The `ttk::ThemeChanged` error is a Tk bug: https://core.tcl-lang.org/tk/info/310c74ecf440 – chrstphrchvz Apr 25 '23 at 12:21

2 Answers2

1

It's usually best to avoid having more than on instance of Tk in your application for the reasons stated in the link in the comment I posted under your question.

So below is code showing one way to do that based on what's in your question. In it the DashboardWindow class is derived from tkinter's Toplevel widget. Note that the MainWindow instance is only hidden so isn't destroyed, which means it could be made visible again (via a root.state('normal') call if desired). To demonstrate that I added a Button to the DashboardWindow class.

import tkinter as tk


class MainWindow(tk.Tk):
    def __init__(self, condition):
        super().__init__()

        self.title("Main Window ")
        self.geometry("640x360")

        if condition == 1:
            new = DashboardWindow(self)
            self.wait_visibility(new)  # Wait until it's visible.
            self.withdraw()  # Hide MainWindow


class DashboardWindow(tk.Toplevel):
    def __init__(self, parent):
        super().__init__(parent)

        self.title("Dashboard Window")
        self.geometry("940x560")

        tk.Button(self, text='Main window', command=lambda: parent.state('normal')).pack()


if __name__ == '__main__':

    root = MainWindow(1)
    root.mainloop()

martineau
  • 119,623
  • 25
  • 170
  • 301
  • Even though the `MainWindow` is hidden it still requires computational power and still lives in memory. Also those 2 windows aren't independent and I disagree with the answer in link you posted. – TheLizzard Sep 05 '21 at 08:46
  • @TheLizzard: I know the hidden window requires some negligible resources — but hardly more than its base class...and that you disagree with linked answer since you've mentioned it before on other questions. Guess we can agree to disagree since I feel Bryan Oakley has more credibility wrt to `tkinter` than you (and I personally have never needed more than one instance). – martineau Sep 05 '21 at 09:21
  • I know that BryanOakley has more credibility than me but I still stand behind my point. If someone can give me am example where creating 2 `tk.Tk` windows causes problems other than the one I said in my question, I will reconsider my point. – TheLizzard Sep 05 '21 at 09:24
  • @TheLizzard: Well, Brian explained to you in more detail [once](https://stackoverflow.com/users/7432/bryan-oakley), plus I think it just makes things more error-prone. However I do agree with you about the OP's design possibly being flawed. It sounds to me like there's a main window and some subsidiary ones, so it doesn't make sense to destroy the primary one because it'll be needed again — which my answer allows and is another reason I think it's the better one thus far (beyond merely the fact that it's following Oakley's advice). – martineau Sep 05 '21 at 09:40
1

Right now you create a tk.Tk window, then call .destory() on it and then call .mainloop() on it. The .destroy() will destroy the window so you can no longer call any normal tkinter methods on it like .mainloop()

This is your code fixed:

import tkinter


class MainWindow(tkinter.Tk):
    def __init__(self, condition):
        super().__init__()

        self.title("Main Window ")
        self.geometry("640x360")

        if (condition == 1):
            new_window = DashboardWindow()
            self.destroy()
            # We will call .mainloop() here:
            new_window.mainloop()


class DashboardWindow(tkinter.Tk):
    def __init__(self):
        super().__init__()

        self.title("Dashboard Window")
        self.geometry("940x560")


# After this is done, the window will no longer be allive so we can't call `.mainloop()`
MainWindow(1)

I think that your design is flawed. You can have multiple tk.Tk windows (so the windows are independent of each other) but you have to pass in master=... when creating PhotoImages/StringVars/IntVars/... And it doesn't matter how many tk.Tk windows you have, don't call any methods on widgets/windows that have been destroyed.

TheLizzard
  • 7,248
  • 2
  • 11
  • 31
  • [You should know better](https://stackoverflow.com/a/67007762/13629335) – Thingamabobs Sep 05 '21 at 09:12
  • 1
    @Atlas435 The `.mainloop()` handles events from all `tk.Tk` windows. So as long as you have 1 `.mainloop()` there shouldn't be any problems. – TheLizzard Sep 05 '21 at 09:14
  • `mainloop()` is called by default. If you run a script without calling mainloop it calls it automatically. – Thingamabobs Sep 05 '21 at 09:16
  • 2
    @Atlas435 No. `.mainloop()` is called by the python interpreter if it's in interactive mode. Try: `import tkinter as tk; root = tk.Tk()` and from CMD use `python filename.py`. The program will end immediately without showing the window. – TheLizzard Sep 05 '21 at 09:19
  • @TheLizzard i get same console error when i close application. to make simple i dont use class in here `root = tkinter.Tk() roo1 = tkinter.Tk() root.destroy() roo1.mainloop()` – david stephen Sep 05 '21 at 09:21
  • @TheLizzard console not error if close manually by click button. but using method destroy give console error. – david stephen Sep 05 '21 at 09:23
  • @davidstephen First you destroy the window then you try calling `.mainloop()` on it. You can't call any `tkinter` methods without the widget still being alive (there are some rare exceptions). That is the problem. – TheLizzard Sep 05 '21 at 09:25
  • @davidstephen if you manually close the window, that happens after the `.mainloop()` has started. – TheLizzard Sep 05 '21 at 09:26
  • Downvoter care to explain? I solved the question and my answer works so why the downvote? – TheLizzard Sep 05 '21 at 09:28
  • @TheLizzard if so, i try put root.destroy() in latest line. it get same error. `root = tkinter.Tk() roo1 = tkinter.Tk() roo1.mainloop() root.destroy()` – david stephen Sep 05 '21 at 09:28
  • @davidstephen In that case you call `root1.mainloop()` which only stops when the user closes the window and the you call `.destroy()`. So you are calling `.destroy()` on a window that has been destroyed by the user. That is still the same problem as before. – TheLizzard Sep 05 '21 at 09:30
  • @TheLizzard mainloop can share to many object tk, right? i try call mainloop first before i call to destroy specific window. – david stephen Sep 05 '21 at 09:30
  • 1
    @TheLizzard I dont want to argue with you once again about this. As I said last time, `tkinter` wasnt designed this way and you cant think this through. Its a bad advice. – Thingamabobs Sep 05 '21 at 09:30
  • @TheLizzard ow, mainloop only listen to widget event ( button, check, radio ), right? mainloop cant listen to programmatically call. – david stephen Sep 05 '21 at 09:31
  • @Atlas435 Care to give me an example where my advice doesn't work? Also this question isn't caused by the multiple instances of `tk.Tk`. The only problem I have seen so far caused by the multiple `tk.Tk` windows is the one where people don't pass in `master=...` when creating their tkinter variables/images. – TheLizzard Sep 05 '21 at 09:33
  • 1
    @davidstephen The `.mainloop()` handles all events from all `tk.Tk` windows but you can only call `.mainloop()` on a window that is still alive. – TheLizzard Sep 05 '21 at 09:34
  • @TheLizzard if like that, is not put root.destroy() in latest line. it should not be problem. root window still exist. second window call main loop method, and it still exist. after root.destroy() call – david stephen Sep 05 '21 at 09:37
  • @davidstephen As I said, you can only call `.mainloop()` on a window that is still alive. If you keep a reference to the `DashboardWindow` and cal `.mainloop()` on that, it should work. – TheLizzard Sep 05 '21 at 09:38
  • 1
    @TheLizzard I dont think this practice is necesarry. Therefore I wont work this idea out with you. – Thingamabobs Sep 05 '21 at 09:40
  • @Atlas435 There are cases where you might want windows that are independent of each other. But if you don't want to argue, I am fine. – TheLizzard Sep 05 '21 at 09:42
  • @TheLizzard as I stated in the first place. For this case you can run 2 scripts simultaneously, without mind all the sideeffects of this practice. – Thingamabobs Sep 05 '21 at 09:44
  • @Atlas435 I assume you mean in multiple processes, then communication between the 2 windows will be difficult. But it is possible to do that. – TheLizzard Sep 05 '21 at 09:46
  • @TheLizzard the method I would prefere depends on what I want to achive. There is no general solution for complexity. – Thingamabobs Sep 05 '21 at 09:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/236779/discussion-between-atlas435-and-thelizzard). – Thingamabobs Sep 05 '21 at 09:53