简体   繁体   中英

Update frame on tab switch in ttk.Notebook

I have a custom Frame with an update method that I want to call every time the user switches tab in a notebook using python2.7 ttk .

My first thought was to intercept some "tab switch event", get the frame from the event and call the update method. However, googling this yields no good results. I can't seem to catch the event, nor get the frame from a "tab click event" in a good way. My current solution below works okay but I'm looking for a better alternative. (Also with my real update method I get some nasty alloc errors).

import ttk
import Tkinter as tk

class MyFrame(ttk.Frame):
    def __init__(self, master, name):
        ttk.Frame.__init__(self, master)
        self.name = name
        self.pack()

    def update(self):
        # Update the contents of the frame...
        print "Updating %s" % self.name

class App():
    def __init__(self):
        root = tk.Tk()

        nb = ttk.Notebook(root)

        f1_name = "Tab1"
        f2_name = "Tab2"
        f1 = MyFrame(nb, f1_name)
        f2 = MyFrame(nb, f2_name)

        nb.add(f1, text=f1_name)
        nb.add(f2, text=f2_name)

        def tab_switch(event):
            if event.widget.identify(event.x, event.y) == "label":
                index = event.widget.index("@%d,%d" % (event.x, event.y))
                title = event.widget.tab(index, "text")

                if title == f1_name:
                    f1.update()
                elif title == f2_name:
                    f2.update()
                # and so on...

        nb.bind("<Button-1>", tab_switch)
        nb.pack(fill="both", expand=True)

        f1.update()  # Initial update of first displayed tab

        root.geometry("200x200")
        root.mainloop()

App()

As you can imagine this becomes very non-DRY as the amount of tabs increases...

You can bind to the <Visibility> or <Map> event of the frame. For example:

class MyFrame(ttk.Frame):
    def __init__(self, master, name):
        ttk.Frame.__init__(self, master)
        self.name = name
        self.pack()
        self.bind("<Visibility>", self.on_visibility)

    def on_visibility(self, event):
        self.update()

Instead of

def tab_switch():
    # see question...

nb.bind("<Button-1>", tab_switch)

you can do the following trick

b.bind("<<NotebookTabChanged>>", 
       lambda event: event.widget.winfo_children()[event.widget.index("current")].update())

This also removes the need to call

f1.update()  # Initial update of first displayed tab

However, the solution proposed by @BryanOakley might work better when you have different types of frames where you cannot be sure if an .update() method exists.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM