【问题标题】:How to update/refresh widgets when switching frames in tkinter?在 tkinter 中切换帧时如何更新/刷新小部件?
【发布时间】:2020-10-10 13:22:28
【问题描述】:

我有一个 gui 应用程序,其中导航栏具有在帧之间切换的按钮。在起始页上有一个用于获取文件名的条目小部件和一个用于显示所有已保存文件名的列表框。当从列表框中选择文件名时,将打开另一个页面,显示所选文件名。

我相信答案here 在开始时会创建框架对象,将它们堆叠起来并提升调用的任何框架。但我认为我的窗口每次被调用时都需要更新,以便它可以显示不同的文件名。它也被放置在与其他框架完全相同的位置,这样我仍然可以使用导航栏按钮切换到其他主页和其他窗口。我发现了类似 here 的东西,但我无法理解。

(我的实际应用比这个复杂一点,但我认为这是我的问题的一个小而精确的表示)

编辑

import tkinter as tk

class MainApplication(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(1, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames={}
        for F in (StartPage,PageOne):
            page_name = F.__name__
            frame = F(parent=container, controller=self)
            self.frames[page_name] = frame
            frame.grid(row=1, column=0, sticky="nsew")

        self.show_frame("StartPage")

    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.list_box = tk.Listbox(self)
        self.list_box.pack()
        for item in ["file 1", "file 2", "file 3"]:
            self.list_box.insert(tk.END, item)
        button1 = tk.Button(self, text='Go to next Page', command=lambda: self.getvalue(controller))
        button1.pack()

    def getvalue(self, controller):
        clicked_item=self.list_box.curselection()
        selected_file=self.list_box.get(clicked_item)
        print(selected_file)
        controller.show_frame('PageOne')

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        # ....selected file name to be displayed here....
        button1 = tk.Button(self, text="Back to Home", command=lambda: controller.show_frame('StartPage'))
        button1.pack()


app = MainApplication()
app.geometry("400x400")
app.mainloop()

【问题讨论】:

  • @stovfl 您建议的答案可以正常工作,但我有一个问题,据我了解,发生的情况是框架相互堆叠,然后在堆叠顺序。但是,在我的应用程序中,我想要的是,当我从 Window 2 切换回 Window 1 时,该窗口的内容会更新或刷新,并且不会与以前保持相同。你知道我该怎么做吗?
  • @stovfl 我已经添加了代码...我不知道每次我想从 StartPage 转到 PageOne 时如何传递 selected_file 名称

标签: tkinter


【解决方案1】:

#Multiple Screens

from tkinter import *

class screen(Frame):
    """
    A screen is area
    for content in a program
    """
    def __init__(self,master,name):
        Frame.__init__(self,master)
        #Attributes
        self.master=master
        self.name=name
        #Initalise with master
        self.master.addScreen(self)
    def show(self):
        """
        Method will show screen
        """
        self.master.showScreen(self.name)

class screenController(Frame):
    """
    Screen Controller
    will manage screens 
    in the program
    """
    def __init__(self,parent):
        Frame.__init__(self,parent)
        #Configure
        self.grid_rowconfigure(0, weight=1)
        self.grid_columnconfigure(0, weight=1)
        #Attributes
        self.allScreens={}
        self.currentScreen=None

    def addScreen(self,screenObject):
        """
        Adds a Screen object to the screenController
        """
        #Place the screen
        screenObject.grid(row=0, column=0, sticky="nsew")
        #Add to dictionary
        self.allScreens[screenObject.name]=screenObject

    def showScreen(self,screenName):
        if screenName in self.allScreens:
            #Display
            self.allScreens[screenName].tkraise()
            #Update variable
            self.currentScreen=screenName
            
    
#Create a Tkinter Window
window=Tk()
window.title("Multiple Screens")
window.geometry("400x300")
window.columnconfigure(0,weight=1)
window.rowconfigure(1,weight=1)


#Create a Controller for the screens
screenMaster=screenController(window)
screenMaster.grid(row=1,column=0,sticky="NSEW")

#Create SCREEN 1
screen1=screen(screenMaster, "S1")
Label(screen1,text="This is screen 1").grid(row=0,column=0) 
screen1.config(bg="red")

#Create SCREEN 2
screen2=screen(screenMaster, "S2")
Label(screen2,text="This is screen 2").grid(row=0,column=0) 
screen2.config(bg="blue")

#Create SCREEN 3
screen3=screen(screenMaster, "S3")
Label(screen3,text="This is screen 3").grid(row=0,column=0) 
screen3.config(bg="green")

#Create a navigation bar
navBar=Frame(window)
navBar.grid(row=0,column=0,sticky="EW")
navBar.config(bg="#F1F0F2")

b1=Button(navBar,text="Screen 1",command=lambda: screen1.show())
b1.grid(row=0,column=0)

b1=Button(navBar,text="Screen 2",command=lambda: screen2.show())
b1.grid(row=0,column=1)

b1=Button(navBar,text="Screen 3",command=lambda: screen3.show())
b1.grid(row=0,column=2)


#Show screen 1 by default
screen1.show()

window.mainloop()

这就是我使用 OO 编程来解决这个问题的方式,导航栏将保持静止,无论您在哪个“屏幕”上,只需将屏幕彼此上方抬起,您就不需要继续创建新对象并节省大量内存。

此解决方案也是非常模块化的,您只需像添加 Tkinter 框架一样添加屏幕。

【讨论】:

    【解决方案2】:

    问题:每次想从StartPage转到PageOne时如何传递selected_file名。


    核心点

    重载类方法Frame.tkraise 以在每次从controller 调用.tkraise 时更新PageOne 小部件

    注意:我只展示了您的示例代码的更改部分,请仔细比较并复制到您的真实代码。


    1. class MainApplication(tk.Tk): 没有变化

      class MainApplication(tk.Tk):
         ...
      
    2. class StartPage(tk.Frame):

      class StartPage(tk.Frame):
          def __init__(self, parent, controller):
              ...
              .Button(..., command=lambda: controller.show_frame('PageOne'))
      
          def getvalue(self):
              ...
              return selected_file
      
      
    3. class PageOne(tk.Frame):

      class StartPage(tk.Frame):
          def __init__(self, parent, controller):
              tk.Frame.__init__(self, parent)
              self.controller = controller
              # ....selected file name to be displayed here....
              self.label = tk.Label(self, text='')
              self.label.pack()
      
          def tkraise(self, aboveThis=None):
              # Get a reference to StartPage
              start_page = self.controller.frames['StartPage']
      
              # Get the selected item from start_page
              self.label.configure(text=start_page.getvalue())
      
              # Call the real .tkraise
              super().tkraise(aboveThis)
      
      

    替代方案

    【讨论】:

    • 非常感谢!终于学会了如何解决问题
    猜你喜欢
    • 1970-01-01
    • 2021-06-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多