python-3.xtkinterobject-oriented-analysistoplevel

Object oriented constructor for Toplevel class (no side-effects)


I'm having trouble writing the constructor for a class that inherits from tkinter's Toplevel dialog. I'm calling it from another class that itself inherits from Frame. The problem I'm getting is a funny side-effect with the code I've come up with. I get an extra instance of the the calling Frame when the Toplevel dialog gets instantiated. I just wanted to ask if somebody could point me in the right direction on how to call super in the constructor for a custom Toplevel class. This inside a Python framework. The entire code I currently have follows:

from tkinter import *
from tkinter import ttk


class App(Frame):

    dialog = None

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

        self.create_widgets()

    def create_widgets(self):

        self.grid(row=3, column=1)
        self.t1 = Text(root, wrap="word")
        self.t1.grid(row=0, column=0, rowspan=2, sticky="nsew")
        self.b1 = Button(root, text=" Create ", command=self.show_dialog)
        self.b1.grid(row=2, column=0, pady=10)

        root.rowconfigure(0, weight=3)
        root.columnconfigure(0, weight=1)

    def show_dialog(self):

        self.dialog = Toplevel(root)
        self.dialog.title("Child")

        # Place child window over the application window
        x = self.root.winfo_x() + self.root.winfo_width()//2 - \
            self.dialog.winfo_width()//2
        y = self.root.winfo_y() + self.root.winfo_height()//2 - \
            self.dialog.winfo_height()//2
        self.dialog.geometry(f"100x75+{x}+{y}")

        Dialog(self.t1, self.dialog)


class Dialog(Toplevel):

    def __init__(self, t1, top):

        super().__init__(top)    # This doesn't work !!!

        self.top = top
        self.t1 = t1    # Text widget is passed at creation

        self.widget()

    def widget(self):
        self.e1 = Entry(self)
        self.e1.grid(row=0, column=0)
        self.b1 = Button(self, text="Submit", command=self.on_submit)
        self.b1.grid(row=1, column=0, pady=15)

        # self.rowconfigure(0, weight=1)

    def on_submit(self):
        self.t1.insert("insert", self.e1.get())

    def quit(self):
        self.top.destroy()


root = Tk()
root.title("Paremt")
root.geometry("400x250+400+200")

app = App(root)
app.mainloop()

I've updated this post to show the entire listing. I'm also trying to improve on it from comments below. I'm still getting the side effects. Now it seems to instantiate two top-level windows instead of just the class.


Solution

  • Thanks for all the help, I was having difficulties applying the knowledge I have of objects in Java to the Python/Tk paradigm. It all seems to work fine now. The updated listing follows.

    from tkinter import *
    from tkinter import ttk
    
    
    class App(Frame):
    
        def __init__(self,  root):
            super(App, self).__init__(root)
    
            self.create_widgets()
    
        def create_widgets(self):
    
            self.t1 = Text(root, wrap="word")
            self.t1.grid(row=0, column=0, rowspan=2, sticky="nsew")
            self.b1 = Button(root, text=" Create ", command=self.show_dialog)
            self.b1.grid(row=2, column=0, pady=10)
    
            root.rowconfigure(0, weight=3)
            root.columnconfigure(0, weight=1)
    
        def show_dialog(self):
    
            Dialog(root, self.t1)
    
        def quit(self):
            self.destroy()
    
    
    class Dialog(Toplevel):
    
        def __init__(self, top, t1):
    
            super().__init__(top)
    
            self.t1 = t1    # Text widget is passed at creation
            self.title("Child")
            # Place child window over the application window
            x = root.winfo_x() + root.winfo_width()//2 - self.winfo_width()//2
            y = root.winfo_y() + root.winfo_height()//2 - self.winfo_height()//2
            self.geometry(f"100x75+{x}+{y}")
    
            self.widget()
            self.wait_visibility()
            self.transient(root)   # dialog window is related to main
    
    
        def widget(self):
            self.e1 = Entry(self)
            self.e1.grid(row=0, column=0)
            self.b1 = Button(self, text="Submit", command=self.on_submit)
            self.b1.grid(row=1, column=0, pady=15)
    
            root.rowconfigure(0, weight=1)
            root.columnconfigure(0, weight=1)   
    
        def on_submit(self):
            self.t1.insert("insert", self.e1.get())
    
        def quit(self):
            self.destroy()
    
    
    root = Tk()
    root.title("Paremt")
    root.geometry("400x250+400+200")
    
    app = App(root)
    app.mainloop()