【问题标题】:Refresh a tkinter frame on button press按下按钮刷新 tkinter 帧
【发布时间】:2017-07-12 18:04:20
【问题描述】:

我正在使用来自 Switch between two frames in tkinter 的代码来制作我的 GUI。我有一个带有刷新和重启按钮的框架。

我最初的想法是让重新启动按钮转到开始页面,如下面的代码所示,但是如果再次调用此框架,它仍然会显示上一次尝试的条目。

我已经为刷新按钮尝试了.destroy(),但是当我再次调用 PLG 框架时,我收到一条回溯消息。

对于重启按钮,我将如何关闭 PLG 框架,进入开始页面,然后能够再次选择 PLG?

对于刷新按钮,我将如何删除条目小部件中的条目和文本拖尾,以便可以输入另一个条目并返回新答案?

class PLG(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        label = tk.Label(self, text="Enter the engine size (cc) below", font=controller.title_font)
        label.pack(side="top", fill="x", pady=10)
        vcmd = (self.register(self.onValidate), '%S')
        self.weight_entry = tk.Entry(self, validate='key', vcmd = vcmd)
        self.weight_entry.pack(pady = 10)
        tk.Button(self, text='Click here to display price', command=self.show_option).pack()
        self.text = tk.Text(self)
        self.text.pack(pady = 10)
        self.text.config(state='disabled')
        restart_button = tk.Button(self, text="Restart",
              command=self.restart)
        restart_button.pack()
        refresh_button = tk.Button(self, text="Refresh", command=self.refresh).pack() 
        refresh_button.pack()  

    def onValidate(self,S):
    if S in ['0','1','2', '3', '4', '5', '6', '7', '8', '9']: 
        return True
    else:
        self.bell() # adds a sound effect to error
        self.text.delete(1.0, tk.END) # deletes the error message if valid entry provided
        self.text.insert(tk.END, "Invalid entry.  Please try again.") # displays an error message if a number not provided in entry widget
        return False

    def restart(self):
        self.refresh()
        show_frame("StartPage")

    def refresh(self):
        self.text.config(state='normal')
        self.weight_entry.delete(0,tk.END)
        self.text.delete("1.0", "end")

我们将不胜感激有关这两个元素的建议。

【问题讨论】:

    标签: python-3.x tkinter


    【解决方案1】:

    OP 的问题是关于清除输入字段,因此当您希望看到新输入的空字段时,先前的输入不会仍在页面中。我正在发布完成的代码,同时省略了与他的问题无关的 OP 原始代码的功能,因此可以在完整的上下文中轻松查看解决方案。我一直在寻求使用 Bryan Oakley 著名的关于该主题的教程中的相同帧切换代码来解决这个问题。我还包括了一个使用 grid_remove 而不是 tkraise 的替代版本,因为这就是我如何解决当用户试图通过页面切换时试图参与焦点遍历的永远活跃但看不见的帧的问题。它还使所有框架都保持相同的大小。

    import tkinter as tk
    
    class SampleApp(tk.Tk):
    
        def __init__(self, *args, **kwargs):
            tk.Tk.__init__(self, *args, **kwargs)
    
            container = tk.Frame(self)
            container.pack(side="top", fill="both", expand=True)
            container.grid_rowconfigure(0, weight=1)
            container.grid_columnconfigure(0, weight=1)
    
            self.frames = {}
    
            # alternate ways to create the frames & append to frames dict: comment out one or the other
    
            for F in (StartPage, PLG):
                page_name = F.__name__
                frame = F(parent=container, controller=self)
                self.frames[page_name] = frame
                frame.grid(row=0, column=0, sticky="nsew")
    
            # self.frames["StartPage"] = StartPage(parent=container, controller=self) 
            # self.frames["PLG"] = PLG(parent=container, controller=self)
            # self.frames["StartPage"].grid(row=0, column=0, sticky="nsew")
            # self.frames["PLG"].grid(row=0, column=0, sticky="nsew")
    
            self.show_frame("StartPage")
    
        # alternate version of show_frame: comment out one or the other
    
        def show_frame(self, page_name):
            for frame in self.frames.values():
                frame.grid_remove()
            frame = self.frames[page_name]
            frame.grid()
    
        # def show_frame(self, page_name):
            # frame = self.frames[page_name]
            # frame.tkraise()
    
    class StartPage(tk.Frame):
    
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
    
            label = tk.Label(self, text="start page")
            label.pack(side="top", fill="x", pady=10)
    
            button1 = tk.Button(self, text="Go to Page One", command=lambda: controller.show_frame("PLG"))
            button1.pack()        
    
            button2 = tk.Button(self, text="focus traversal demo only")
            button2.pack()
            button2.focus_set()
    
            button3 = tk.Button(self, text="another dummy button")
            button3.pack()
    
            lbl = tk.Label(self, text="tkraise messes up focus traversal\nwhich you can see by testing the two versions of show_frame.()\nUsing grid_remove instead of tkraise solves that,\nwhile preventing frames from being unable to resize to fit their own contents.")
            lbl.pack()
    
    class PLG(tk.Frame):
        def __init__(self, parent, controller):
            tk.Frame.__init__(self, parent)
            self.controller = controller
            label = tk.Label(self, text="Enter something below; the two buttons clear what you type.")
            label.pack(side="top", fill="x", pady=10)
            self.wentry = tk.Entry(self)
            self.wentry.pack(pady = 10)
            self.text = tk.Text(self)
            self.text.pack(pady = 10)
            restart_button = tk.Button(self, text="Restart", command=self.restart)
            restart_button.pack()
            refresh_button = tk.Button(self, text="Refresh", command=self.refresh) 
            refresh_button.pack()  
    
        def restart(self):
            self.refresh()
            self.controller.show_frame("StartPage")
    
        def refresh(self):
            self.wentry.delete(0, "end")
            self.text.delete("1.0", "end")
            # set focus to any widget except a Text widget so focus doesn't get stuck in a Text widget when page hides
            self.wentry.focus_set()
    
    if __name__ == "__main__":
        app = SampleApp()
        app.mainloop()
    

    【讨论】:

      【解决方案2】:

      第一步是让您的按钮调用正确的函数,而不是使用lambda。除非您了解为什么以及何时使用lambda,否则它通常只会使代码更难编写和理解。

      一旦你让它调用一个函数,你就可以使用该函数来清除条目。

      例子:

      class PLG(tk.Frame):
          def __init__(self, parent, controller):
              ...
              tk.Button(self, text="Restart", command=self.restart)
              tk.Button(self, text="Refresh", command=self.refresh)
              ...
      
          def restart(self):
              self.refresh()
              self.controller.show_frame("StartPage")
      
          def refresh(self):
              self.weight_entry.delete(0, "end")
              self.text.delete("1.0", "end")
      

      【讨论】:

      • 感谢 Bryan,但我在条目小部件中只允许 0-9 的功能正在阻止条目小部件被清除。
      • 我已经编辑了我的代码以包含验证代码,阻止@Bryan Oakley 提出的解决方案发挥作用。
      • @bagpuss:您只需要修复您的验证脚本以允许使用空字符串。
      • 已解决刷新问题,但您的 def 重启不起作用。 AttributeError:“PLG”对象没有属性“show_frame”。您能否提供进一步的帮助,或者这是现在要针对 SO 提出的一个新问题?
      • @bagpuss:我只是在复制你的代码。我会用有根据的猜测来更新我的答案。
      【解决方案3】:

      简单的方法: 只需使用按钮调用该窗口或绑定框架所在的窗口即可。

      适用于 Windows 刷新。

      【讨论】:

        猜你喜欢
        • 2019-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多