在Tkinter中切换框架时如何更新/刷新小部件?

时间:2020-06-20 10:35:45

标签: tkinter

我有一个gui应用程序,其中导航栏具有在帧之间切换的按钮。在起始页上,有一个输入小部件以获取文件名,以及一个列表框以显示所有保存的文件名。从列表框中选择文件名后,会打开另一个页面,其中显示所选文件名。enter image description here

我相信答案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()

2 个答案:

答案 0 :(得分:2)

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


核心点

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

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


  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)
    
    

替代

答案 1 :(得分: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框架一样。