【问题标题】:Tkinter example code for multiple windows, why won't buttons load correctly?用于多个窗口的 Tkinter 示例代码,为什么按钮无法正确加载?
【发布时间】:2013-04-13 11:33:56
【问题描述】:

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

  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()

【问题讨论】:

    标签: python class tkinter destroy


    【解决方案1】:

    我以更有条理、更实用的方式重写了您的代码:

    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()
    

    结果:

    【讨论】:

    • @ADB 这取决于。一般情况下,在两个Tk()窗口上运行两个mainloop()s是被看不起的。但是,如果您想要多个窗口,则可以避免两个mainloop()s。因此,您可以使用类似于Tk()Toplevel() 小部件。
    • 两个主循环不“依赖”任何东西,它不仅仅是“看不起”,它完全是错误的。你只需要一个。对 mainloop 的调用是一个无限循环,当您运行多个循环时,您在无限循环中就有一个无限循环。您应该在代码中(在 Demo1.new_window 中)删除对 mainloop 的第二次调用,否则会令尝试学习如何使用 Tkinter 的人感到困惑。
    • 你能解释一下close_windows()吗?什么时候必须调用它?
    • @sbhatla close_window() 在单击类Demo2 的“退出”按钮时被调用。使用tk.Button() 中的参数command 创建此链接。
    • 您决定不让class Demo1() 继承tk.Frame 有什么原因吗?
    【解决方案2】:

    您需要为第二个按钮指定主按钮。否则它将被打包到第一个窗口中。这不仅对于Button 是必需的,对于其他小部件和非gui 对象(例如StringVar)也需要。

    快速修复: 将框架 new 作为第一个参数添加到 Demo2 中的 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。选择前两个 import 语句之一。

    【讨论】:

      【解决方案3】:
      #!/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()
      

      【讨论】:

        【解决方案4】:

        我尝试使用上面的 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()
        

        新窗口只打开一次

        为了避免多次按下具有多个窗口的按钮......这是同一个窗口,我制作了这个脚本(也可以查看this page

        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()
        

        【讨论】:

          【解决方案5】:

          您可以将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)
          

          你有两个不碰撞的窗口!

          【讨论】:

          • 多么糟糕的主意。动态创建多个窗口怎么样?使用您的方法,您需要动态复制 tkinter.py 并将其副本添加到 python 路径,然后从导入的文件中获取适当的类,更不用说在某些情况下您需要在某处保留对 UI 元素的引用,以便GC 不会摆脱它们......不,只是不。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2012-10-04
          • 1970-01-01
          • 1970-01-01
          • 2020-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多