0

In my Tkinter chatbot app, clicking the 'History' menu opens a new window every time. How can I make it so only one history window exists, and if it's already open, bring it to focus instead of opening another?

my history window code:

def show_history():
    win.withdraw()

    def open_file(file_path, text_widget):
        try:
            with open(file_path, "r", encoding="utf-8") as file:
                content = file.read()
                text_widget.delete("1.0", "end")
                text_widget.insert("1.0", content)
        except FileNotFoundError:
            text_widget.delete("1.0", "end")
            text_widget.insert("1.0", f"Error: File not found at {file_path}")
        except Exception as e:
            text_widget.delete("1.0", "end")
            text_widget.insert("1.0", f"An error occurred: {e}")

    def close_new_window():
        root.destroy()
        win.deiconify()

    root = ctk.CTkToplevel()
    root.geometry(f"{HEIGHT}x{WIDTH}")

    file_content_textbox = ctk.CTkTextbox(root, wrap="word")
    file_content_textbox.pack(fill="both", expand=True, padx=10, pady=10)

    file_to_load = resource_path("data.txt")

    open_file(file_to_load, file_content_textbox)

    button = ctk.CTkButton(root, text="Close", command=close_new_window)
    button.pack(pady=50)

    root.mainloop()
2
  • Please post a minimal reproducible example. There's no "History" menu and there are several undefined variables. Commented Aug 6 at 10:55
  • 1
    BTW: in tkinter should be only one mainloop because second mainloop can make problem with values in variables - because one mainloop can get values/events and other may not find them. Commented Aug 6 at 11:25

1 Answer 1

2

First: you have to keep open window in global variable to have access to previous window. Because you probably already have root to keep main window Tk() so new variable need different name - ie. history_window

At start you can set history_window as None and when you click button then you have to check if history_window is None. If history_window is None then create window and assign to history_window. When it is not None then you can use history_window.deiconify() to show it.

And when you destroy this window then you may have to set history_window again None.

Something similar to:

history_window = None  # created outside all functions 

def show_history():
    global history_window   # use external/global variable 
                            # to keep access to window

    def close_new_window():
        history_window.destroy()
        history_window = None

        win.deiconify()

    if history_window is None:
        # create new window
        history_window = ctk.CTkToplevel()

        # ... rest of code
       
        # ... probably without `mainloop()`

    else:
        # show existing window
        history_window.deiconify()

    #file_to_load = resource_path("data.txt")
    #open_file(file_to_load, file_content_textbox)

Probably in else: you may have to load history again and replace content in existing window.

Normally tkinter needs only one mainloop because second mainloop can makes conflict - some values in widgets may be accessed by wrong mainloop and they may not be displayed. And when there is no mainloop in show_history then open_file can be after if/else

In close_new_window() you may also use history_window.withdraw() (instead destroy() and history_window = None) to only hide window.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.