简体   繁体   中英

Python Tkinter communicate through multiple windows and return values after destroy

I want to make a program with multiple tkinter windows, but i encounter some problems. I have a main window containing one button. After pressing that button, a toplevel will open which contain widgets through user input some data. This toplevel also contain a button that, once pressed, the toplevel is destroyed and the data introduced is returned to the function called by the event from the first button. The main window is destroyed and the data is passed as an argument to a third window who will use it.

from tkinter import *


def third_window(data):
    root = Tk()

    lbl = Label(root, text=data)
    lbl.place(x=20,y=20)

    root.mainloop()

def second_window():
    def event_btn(event):
        e = entry.get()
        if len(e) != 0:
            root.destroy()
            print(e)
            return e
    root = Toplevel()
    root.geometry("400x400+200+200")

    entry = Entry(root, width=15)
    entry.place(x=30,y=30)
    btn = Button(root, text="Send")
    btn.bind("<Button-1>", event_btn)
    btn.place(x=80, y=80)
    root.wait_window()

    root.mainloop()

def main():
    def event_btn(event):
        data = second_window()
        print(data)
        root.destroy()
        third_window(data)
    root = Tk()
    root.geometry("200x200+100+100")

    btn = Button(root, text="Test button")
    btn.bind("<Button-1>", event_btn)   
    btn.place(x=50, y=50)

    root.mainloop()

if __name__ == "__main__":
    main()

I encounter 2 problems: the main window isn't closing after the toplevel is destroyed and the data from toplevel is not returned.

One way you could do this is to hide the root window use a top level window and then update that window. This lets us condense things down a lot.

import tkinter as tk

def second_window():
    root.withdraw()
    top = tk.Toplevel(root)
    top.geometry("400x400+200+200")
    entry = tk.Entry(top, width=15)
    entry.place(x=30,y=30)

    def actions():
        x = entry.get()
        entry.destroy()
        btn.destroy()
        tk.Label(top, text=x).place(x=20,y=20)

    btn = tk.Button(top, text="Send", command=actions)
    btn.place(x=80, y=80)


if __name__ == "__main__":
    root = tk.Tk()
    root.geometry("200x200+100+100")
    tk.Button(root, text="Test button", command=second_window).place(x=50, y=50)
    root.mainloop()

Personally I prefer an OOP approach and it makes thing easier to manager down the road.

import tkinter as tk

class Example(tk.Tk):
    def __init__(self):
        super().__init__()
        self.geometry("200x200+100+100")
        self.btn = tk.Button(self, text="Test button", command=self.update_window)
        self.btn.place(x=50, y=50)

    def update_window(self):
        self.geometry("400x400+200+200")
        self.entry = tk.Entry(self, width=15)
        self.entry.place(x=30,y=30)
        self.btn.config(text="Send", command=self.actions)
        self.btn.place(x=80, y=80)

    def actions(self):
        tk.Label(self, text=self.entry.get()).place(x=20,y=20)
        self.btn.destroy()
        self.entry.destroy()

if __name__ == "__main__":
    Example().mainloop()

That said you probably don't need to use place. You will be able to get the look you need from grid() or pack() once you learn how to use them properly.

One way to get it to work is simply withdraw the root window instead of destroying it, and use a StringVar to pass the data instead.

You could also simply rewrite the root with your new layout, if you no longer need what is on it, I would look around at other examples.

One of the main problems you're facing right now is destroying the TopLevel, before the data is passed to the root, but destroying after the return call will ignore the destroy, and it doesn't like passing the TopLevel to the root, for me anyway.

I don't really understand why you're preferring <bind> over the command attribute for the buttons.

from tkinter import *

def third_window(data):
    top = Toplevel()
    lbl = Label(top, text=data)
    lbl.place(x=20,y=20)
    top.wait_window()

def second_window(root, v):
    def event_btn():
        if len(v.get()) != 0:
            top.destroy()
    top = Toplevel()
    top.geometry("400x400+200+200")

    entry = Entry(top, textvariable = v, width=15)
    entry.place(x=30,y=30)
    btn = Button(top, text="Send", command = event_btn)
    btn.place(x=80, y=80)
    root.wait_window(top)

def main():
    def event_btn():
        second_window(root, v)
        print(v.get())
        root.withdraw()
        third_window(v.get())
    root = Tk()
    root.geometry("200x200+100+100")

    btn = Button(root, text="Test button", command = event_btn) 
    btn.place(x=50, y=50)

    v = StringVar()
    root.mainloop()

if __name__ == "__main__":
    main()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM