Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
120 views
in Technique[技术] by (71.8m points)

python - New instance of toplevel classes make overlapping widgets

I'm generally new to python and tkinter. I've been programming maybe about a year or so, and I've just started to try to make each tkinter toplevel window its own class because I've heard that it's the right way to do it.

I'm making a program in which I have a treeview with a button to add contents to it. The button opens up a new window that allows the user to input the contents. The problem I'm having is when I have to instantiate the first window to update the treeview, it seems like it's doubling all of the widgets on the first window. This causes it to keep building up and it looks strange.

Is this normal or is there a better way to do it?

Thank you. I can post a picture or my code if necessary.

edit: shortened code

from tkinter import *
from tkinter import ttk


class MainWindow:
    Items = {'test': ['Material', '500']}
    def __init__(self, master):
        self.master = master

        self.style = ttk.Style()
        self.style.configure('TLabel', font=12)

        ttk.Label(self.master, text="Items").grid(row=0, column=0, columnspan=3)

        self.frmItems = ttk.Frame(self.master)
        self.frmItems.grid(row=1, column=0, padx=5, pady=5, columnspan=3)

        self.treeItems = ttk.Treeview(self.frmItems, columns=(0, 1, 2))
        self.treeItems.column('#0', width=0, minwidth=0)
        self.treeItems.column(1, width=80)
        self.treeItems.column(2, width=80)
        self.treeItems.heading(0, text="Name")
        self.treeItems.heading(1, text="Type")
        self.treeItems.heading(2, text="Price")
        self.treeItems.grid(row=0, column=0)

        self.itemscroll = ttk.Scrollbar(self.frmItems, command=self.treeItems.yview)
        self.itemscroll.grid(row=0, column=1, sticky='ns')
        self.treeItems.config(yscrollcommand=self.itemscroll.set)

        ttk.Button(self.master, text="New", command=self.item_input_show).grid(row=2, column=0, padx=5, pady=5,
                                                                              sticky='e')
        ttk.Button(self.master, text="Edit").grid(row=2, column=1, padx=5, pady=5)
        ttk.Button(self.master, text="Remove").grid(row=2, column=2, padx=5, pady=5, sticky='w')

    def item_input_show(self):
        ItemInput(self.master)


class ItemInput:
    def __init__(self, master):
        self.master = master
        self.MainWindow = MainWindow(master)

        self.topItemInput = Toplevel(self.master)
        self.topItemInput.title("Input Item Properties")


def main():
    root = Tk()
    MainWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You are calling class MainWindow: every time you press the New Button. This is remaking all the widgets over and over. And they way you are creating the MainWindow is affecting how you can interact with MainWindow.

Change:

def main():
    root = Tk()
    MainWindow(root)
    root.mainloop()

if __name__ == "__main__":
    main()

To:

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

Once you have made this change you are able to interact with the instance attributes and methods of main

Below is a modified version of your code. You will notice when you press the button I added to the TopLevel window it will print information from an atribute and method of main variable. It will also place some text in the entry box in the MainWindow.

from tkinter import *
from tkinter import ttk

class MainWindow:
    def __init__(self, master):
        self.master = master
        self.btn = ttk.Button(self.master, text="New", command=self.item_input_show)
        self.btn.pack(side = TOP)
        self.entry = Entry(self.master)
        self.entry.pack(side = BOTTOM)
        self.numbers = 200

    def two_plus_x(self, x):
        math = 2 + x
        return math

    def item_input_show(self):
        ItemInput(self.master)


class ItemInput:
    def __init__(self, master):
        self.master = master
        self.topItemInput = Toplevel(master)
        self.btn = ttk.Button(self.topItemInput, text="Use method in MainWindow", command = self.do_something_from_main)
        self.btn.pack()

    def do_something_from_main(self):
        print(main.numbers)
        print(main.two_plus_x(10))
        main.entry.delete(0, END)
        main.entry.insert(0, "From ItemInput Class")

# notice I removed def main(): as it was preventing us from interacting with the main variable.
if __name__ == "__main__":
    root = Tk()
    main = MainWindow(root)
    root.mainloop()

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...