Stat
Stat

Reputation: 681

tkinter: How to print a list when a Button is clicked?

I am using tkinter and my goal is to print list L inside class Page2(Page) whenever I click on Page 2. Currently, if you run the code, you can see that letters A & B are being printed in the console once you are in Page 1 which means that tkinter has already gone through that for loop. How can I change this code to go through that for loop only if I click on Page 2? FYI, I borrowed the code from the answer to Using buttons in Tkinter to navigate to different pages of the application?.

import tkinter as tk

class Page(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
    def show(self):
        self.lift()

class Page1(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 1")
       label.pack(side="top", fill="both", expand=True)

class Page2(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       L=[]
       for x in ["A","B"]:
           print(x)
           L.append(x)
       label = tk.Label(self, text=L)
       label.pack(side="top", fill="both", expand=True)


class Page3(Page):
   def __init__(self, *args, **kwargs):
       Page.__init__(self, *args, **kwargs)
       label = tk.Label(self, text="This is page 3")
       label.pack(side="top", fill="both", expand=True)

class MainView(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)
        p1 = Page1(self)
        p2 = Page2(self)
        p3 = Page3(self)

        buttonframe = tk.Frame(self)
        container = tk.Frame(self)
        buttonframe.pack(side="top", fill="x", expand=False)
        container.pack(side="top", fill="both", expand=True)

        p1.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p2.place(in_=container, x=0, y=0, relwidth=1, relheight=1)
        p3.place(in_=container, x=0, y=0, relwidth=1, relheight=1)

        b1 = tk.Button(buttonframe, text="Page 1", command=p1.lift)
        b2 = tk.Button(buttonframe, text="Page 2", command=p2.lift)
        b3 = tk.Button(buttonframe, text="Page 3", command=p3.lift)

        b1.pack(side="left")
        b2.pack(side="left")
        b3.pack(side="left")

        p1.show()

if __name__ == "__main__":
    root = tk.Tk()
    main = MainView(root)
    main.pack(side="top", fill="both", expand=True)
    root.wm_geometry("400x400")
    root.mainloop()

Upvotes: 1

Views: 874

Answers (1)

martineau
martineau

Reputation: 123531

It's printing the list because that's part of creating an instance of the Page2 class that occurs before it's made visible (if ever) — which is just an artifact of the architecture of the code in the answer you "borrowed".

Here's a way to fix things. First change the Button callback command= options in MainView.__init__() so the show() method will get called instead of lift():

        b1 = tk.Button(buttonframe, text="Page 1", command=p1.show)
        b2 = tk.Button(buttonframe, text="Page 2", command=p2.show)
        b3 = tk.Button(buttonframe, text="Page 3", command=p3.show)

This means that each Page subclass' show() method will now be invoked whenever one of the Buttons is clicked, which by default just calls its base class' lift() method, so all this does is add a level of indirection — thereby making it possible to easily override / extend it in subclasses like Page2 to make them do whatever specialized processing might be needed.

Note that I also made L an attribute of the subclass' instances (instead of it being a local variable in the the __init__() method) to allow it to be easily referenced in the other method of the class.

class Page2(Page):
    def __init__(self, *args, **kwargs):
        Page.__init__(self, *args, **kwargs)
        self.L = []
        for x in ["A","B"]:
            self.L.append(x)
        label = tk.Label(self, text=self.L)
        label.pack(side="top", fill="both", expand=True)

    def show(self):
        print(f'in class {type(self).__name__}.show()')
        super().show()  # Call superclass' method.
        for x in self.L:
            print(x)

Upvotes: 1

Related Questions