0

Using tkinter, I'm trying to open one window from another window and doing so by creating the windows in a class.

This question talks about tkinter and class, but not multiple windows: Python Tkinter with classes

This question addresses multiple windows but it's creating an instance of the class: Python tkinter multiple windows. I don't want to create an instance of the class because tkdoc.com has the root = Tk() being passed into the class rather than creating an instance.

So, I have this example from https://www.pythontutorial.net/tkinter/tkinter-toplevel/ which does what I want but it creates a subclass of tk.TK rather than passing in root. I'm trying to adapt this example to pass in root because that's what the official docs do.

Here's the example of one window opening up another window that works, but it creates a subclass of tk.Tk:

import tkinter as tk
from tkinter import ttk


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

        self.geometry('300x100')
        self.title('Toplevel Window')

        ttk.Button(self,
                text='Close',
                command=self.destroy).pack(expand=True)


class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.geometry('300x200')
        self.title('Main Window')

        # place a button on the root window
        ttk.Button(self,
                text='Open a window',
                command=self.open_window).pack(expand=True)

    def open_window(self):
        window = Window(self)
        window.grab_set()


if __name__ == "__main__":
    app = App()
    app.mainloop()

Here's my adaptation:

from tkinter import *
from tkinter import ttk


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

        self.geometry('300x100')
        self.title('Toplevel Window')

        ttk.Button(self,
                text='Close',
                command=self.destroy).pack(expand=True)


class App():
    def __init__(self, root):
        super().__init__()

        root.geometry('300x200')
        root.title('Main Window')

        # place a button on the root window
        ttk.Button(root,
                text='Open a window',
                command=self.open_window).pack(expand=True)

    def open_window(self):
        window = Window(self)
        window.grab_set()


if __name__ == "__main__":
    root = Tk()
    App(root)
    root.mainloop()

The first window opens fine (class App()). I'm getting an AttributeError that occurs when attempting to open the second window (class Window(Toplevel)). Yet, the AttributeError is on the first window.

Traceback (most recent call last):
  File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1948, in __call__        
    return self.func(*args)
           ^^^^^^^^^^^^^^^^
  File "c:\Users\User\Documents\Python\Python_Tutorial_net\Multiple_Windows_pass-in-Class.py", line 30, in open_window
    window = Window(self)
             ^^^^^^^^^^^^
  File "c:\Users\User\Documents\Python\Python_Tutorial_net\Multiple_Windows_pass-in-Class.py", line 7, in __init__
    super().__init__(parent)
  File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2678, in __init__
    BaseWidget.__init__(self, master, 'toplevel', cnf, {}, extra)
  File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2623, in __init__
    self._setup(master, cnf)
  File "C:\Users\User\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 2592, in _setup
    self.tk = master.tk
              ^^^^^^^^^
AttributeError: 'App' object has no attribute 'tk'
4
  • It is because instance of App is not a tkinter widget. Parent of tkinter widget should be a widget as well. Commented May 17, 2024 at 0:30
  • @acw1668 are you saying that when I pass root into App(root), then I have not created a tkinter widget? But in the first example, App(tk,TK) is a subclass of tk.Tk so that is a widget? However, the first window created by App(root) does appear. Commented May 17, 2024 at 0:56
  • The first window root is created by root = Tk(), not App(root). Commented May 17, 2024 at 0:59
  • @acw1668 Thanks. That makes sense. So the second window is created by Window(self) calling class Window(Toplevel) which is a subclass of Toplevel? It closes fine with the self.destroy command in that class. Commented May 17, 2024 at 1:26

1 Answer 1

1

Note that instance of App() is not a tkinter widget, so it cannot be used as the parent of the second window.

Use the root window as the parent of the second window instead:

class App():
    def __init__(self, root):
        super().__init__()
        self.root = root   # save root to an instance variable
        ...

    def open_window(self):
        window = Window(self.root)  # used self.root instead of self
        window.grab_set()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.