Tkinter多窗口示例代码,为什么按钮无法正确加载?

44

我正在编写一个程序,它应该能够:

  1. 按下按钮后打开一个窗口。
  2. 按下另一个按钮后关闭新打开的窗口。

我使用类来将代码插入到稍后的更大程序中。然而,我无法正确加载我的按钮。

import tkinter as tk

class Demo1(tk.Frame):
    def __init__(self):
        tk.Frame.__init__(self)
        self.pack()
        self.master.title("Demo 1")
        self.button1 = tk.Button(self, text = "Button 1", width = 25,
                               command = self.new_window)
        self.button1.grid(row = 0, column = 1, columnspan = 2, sticky = tk.W+tk.E+tk.N+tk.S)

    def new_window(self):
        self.newWindow = Demo2()

class Demo2(tk.Frame):
    def __init__(self):
        new = tk.Frame.__init__(self)
        new = tk.Toplevel(self)
        new.title("Demo 2")
        new.button = tk.Button(text = "Button 2", width = 25,
                               command = self.close_window)
        new.button.pack()

    def close_window(self):
        self.destroy()

def main():
    Demo1().mainloop()

if __name__ == '__main__':
    main()
5个回答

71

我按更有组织、更好实践的方式重写了你的代码:

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.button1 = tk.Button(self.frame, text = 'New Window', width = 25, command = self.new_window)
        self.button1.pack()
        self.frame.pack()

    def new_window(self):
        self.newWindow = tk.Toplevel(self.master)
        self.app = Demo2(self.newWindow)

class Demo2:
    def __init__(self, master):
        self.master = master
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()

def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

结果:

演示1窗口 演示2窗口


@ADB 这要看情况。通常来说,在两个 Tk() 窗口上运行两个 mainloop() 是不被推荐的。但是,如果你想要多个窗口,可以避免使用两个 mainloop()。因此,你可以使用类似于 Tk()Toplevel() 小部件。 - Rushy Panchal
16
两个主循环并不“依赖”于任何东西,也不仅仅是被“看轻”,它是完全错误的。你只需要一个主循环。调用 mainloop 就是一个无限循环,当你运行超过一个时,你就会在一个无限循环内部有另一个无限循环。你应该在你的代码(在 Demo1.new_window)中删除第二个 mainloop 的调用,否则对于那些试图学习如何使用 Tkinter 的人来说将会很困惑。 - Bryan Oakley
你能解释一下 close_windows() 吗?它什么时候需要被调用? - sbhatla
当类Demo2的“Quit”按钮被单击时,将调用close_window()。使用tk.Button()中的参数command创建此链接。 - Robin
你决定不让class Demo1()继承tk.Frame有什么原因吗? - Stevoisiak

13

第二个按钮需要指定主窗口,否则它会被添加到第一个窗口。这不仅适用于 Button,还适用于其他小部件和非 GUI 对象,例如 StringVar

快速修复:Demo2 中将帧 new 作为第一个参数添加到您的 Button

可能更好的解决方案:目前,您让 Demo2 继承自 tk.Frame,但我认为如果您将 Demo2 改为类似于以下内容,则更有意义:

class Demo2(tk.Toplevel):     
    def __init__(self):
        tk.Toplevel.__init__(self)
        self.title("Demo 2")
        self.button = tk.Button(self, text="Button 2", # specified self as master
                                width=25, command=self.close_window)
        self.button.pack()

    def close_window(self):
        self.destroy()

作为建议,您应该只导入tkinter一次。选择您的前两个导入语句中的一个。


4
#!/usr/bin/env python
import Tkinter as tk

from Tkinter import *

class windowclass():

        def __init__(self,master):
                self.master = master
                self.frame = tk.Frame(master)
                self.lbl = Label(master , text = "Label")
                self.lbl.pack()
                self.btn = Button(master , text = "Button" , command = self.command )
                self.btn.pack()
                self.frame.pack()

        def command(self):
                print 'Button is pressed!'

                self.newWindow = tk.Toplevel(self.master)
                self.app = windowclass1(self.newWindow)

class windowclass1():

        def __init__(self , master):
                self.master = master
                self.frame = tk.Frame(master)
                master.title("a")
                self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25 , command = self.close_window)
                self.quitButton.pack()
                self.frame.pack()


        def close_window(self):
                self.master.destroy()


root = Tk()

root.title("window")

root.geometry("350x50")

cls = windowclass(root)

root.mainloop()

2

我尝试使用Rushy Panchal上面的例子来使用超过两个窗口。目的是通过调用带有不同小部件的多个窗口进行更改。butnew函数创建不同的按钮以打开不同的窗口。您将包含窗口的类的名称作为参数传递(第二个参数不是必需的,我只是将其放在那里以测试可能的用途。从另一个窗口继承共同的小部件可能很有趣。

最初的回答:

我尝试使用 Rushy Panchal 上面的示例来打开超过两个窗口。我的目的是通过调用拥有不同小部件的多个窗口来进行更改。butnew 函数会创建不同的按钮以打开不同的窗口。您需要将包含窗口的类的名称作为参数传递(第二个参数不是必须的,只是为了测试可能的用途)。从另一个窗口继承相同的小部件可能会很有用。

import tkinter as tk

class Demo1:
    def __init__(self, master):
        self.master = master
        self.master.geometry("400x400")
        self.frame = tk.Frame(self.master)
        self.butnew("Window 1", "ONE", Demo2)
        self.butnew("Window 2", "TWO", Demo3)
        self.frame.pack()

    def butnew(self, text, number, _class):
        tk.Button(self.frame, text = text, width = 25, command = lambda: self.new_window(number, _class)).pack()

    def new_window(self, number, _class):
        self.newWindow = tk.Toplevel(self.master)
        _class(self.newWindow, number)


class Demo2:
    def __init__(self, master, number):
        self.master = master
        self.master.geometry("400x400+400+400")
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.label = tk.Label(master, text=f"this is window number {number}")
        self.label.pack()
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()

class Demo3:
    def __init__(self, master, number):
        self.master = master
        self.master.geometry("400x400+400+400")
        self.frame = tk.Frame(self.master)
        self.quitButton = tk.Button(self.frame, text = 'Quit', width = 25, command = self.close_windows)
        self.label = tk.Label(master, text=f"this is window number {number}")
        self.label.pack()
        self.label2 = tk.Label(master, text="THIS IS HERE TO DIFFERENTIATE THIS WINDOW")
        self.label2.pack()
        self.quitButton.pack()
        self.frame.pack()

    def close_windows(self):
        self.master.destroy()




def main(): 
    root = tk.Tk()
    app = Demo1(root)
    root.mainloop()

if __name__ == '__main__':
    main()

只打开一个新窗口

为了避免多次按下按钮而打开多个相同的窗口,我编写了这个脚本(也可以查看这个页面)。

import tkinter as tk


def new_window1():
    global win1
    try:
        if win1.state() == "normal": win1.focus()
    except:
        win1 = tk.Toplevel()
        win1.geometry("300x300+500+200")
        win1["bg"] = "navy"
        lb = tk.Label(win1, text="Hello")
        lb.pack()


win = tk.Tk()
win.geometry("200x200+200+100")
button = tk.Button(win, text="Open new Window")
button['command'] = new_window1
button.pack()
win.mainloop()

-2
你可以将tkinter.py中的代码复制到一个名为mytkinter.py的文件中,然后使用以下代码:
import tkinter, mytkinter
root = tkinter.Tk()
window = mytkinter.Tk()
button = mytkinter.Button(window, text="Search", width = 7,
                               command=cmd)
button2 = tkinter.Button(root, text="Search", width = 7,
                               command=cmdtwo)

而且你有两个不会碰撞的窗口!


2
多么糟糕的想法。那创建多个动态窗口怎么办?按照您的方法,您将需要动态复制tkinter.py并将其添加到Python路径中,然后从导入的文件中获取正确的类,更不用说在某些情况下您需要在某处保留对UI元素的引用,以便GC不会将它们丢弃...不行,绝对不行。 - user7346816

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接