0

It is fine to do with AMClass[0] or [1] or [2]

    AMClass=[StockProfilePage, BalancePage,AccountSettingsPage]
    AMCommandList=[]
        for i in range (len(AMClass)):
            AMCommandList.append(lambda: self.show_frame(AMClass[1]))

but it shows Exception in Tkinter callback and indexError when I change the number into [i]

    AMClass=[StockProfilePage, BalancePage,AccountSettingsPage]
    AMCommandList=[]
        for i in range (len(AMClass)):
            AMCommandList.append(lambda: self.show_frame(AMClass[i]))

Error:

Exception in Tkinter callback Traceback (most recent call last): File "C:\Users\AppData\Local\Programs\Python\Python38-32\lib\tkinter_init_.py", line 1883, in call return self.func(*args) File "C:\Users\Desktop\Python\2020oop.py", line 50, in f=lambda: self.show_frame(AMClass[i]) IndexError: list index out of range

Here is the minimal reproducible example: this one is workable which is not using [i] in AMClass[]

import tkinter as tk
LARGE_FONT = ("Verdana", 20)
class Stock(tk.Tk):
    def __init__(self,*args,**kwargs):

        tk.Tk.__init__(self,*args,**kwargs)
        #tk.Tk.iconbitmap(self,default="name.ico")
        container = tk.Frame(self)
        container.pack(side="top", fill="both", expand=True)
        menubar = tk.Menu(container)
        AccountMenu = tk.Menu(menubar, tearoff = 0)

        AccountLabelList=["Stock Profile","Balance","Account Settings"]
        AMClass=[StockProfilePage, BalancePage,AccountSettingsPage]
        AMCommandList=[]

        for i in range (len(AMClass)):

            AMCommandList.append(lambda: self.show_frame(AMClass[0]))

        menubar.add_cascade(label="Account",menu=AccountMenu)

        for i in range(len(AccountLabelList)):
            AccountMenu.add_command(label=AccountLabelList[i],command = AMCommandList[i])
        tk.Tk.config(self, menu=menubar)

        self.frames ={}

        for F in (StartPage, StockProfilePage, BalancePage, AccountSettingsPage):

            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column = 0, sticky="NSEW")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()

class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        label = tk.Label(self, text="Start Page", font=LARGE_FONT)
        label.pack(pady=10,padx=10)



class StockProfilePage (tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Stock Profile", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

class BalancePage(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Balance", font=LARGE_FONT)
        label.pack(pady=10,padx=10)

class AccountSettingsPage(tk.Frame):

    def __init__(self,parent,controller):
        tk.Frame.__init__(self,parent)
        label = tk.Label(self, text="Account Setting", font=LARGE_FONT)
        label.pack(pady=10,padx=10)
app = Stock()
app.mainloop()

kj93
  • 9
  • 2
  • 1
    Can you show a [mcve]? – Sweeper Feb 05 '20 at 07:16
  • Your minimal example does not produce the mentioned exception even changed `AMClass[0]` to `AMClass[i]`. Your minimal example will work fine by changing `lambda: self.show_frame(AMClass[0])` to `lambda i=i: self.show_frame(AMClass[i])`. – acw1668 Feb 05 '20 at 08:23
  • @acw1668 Thank you for ur comment. It's useful, but may I know what's the reason behind? – kj93 Feb 05 '20 at 08:30
  • For your original design, when the lambda is called, it will execute `self.show_frame(AMClass[i])` using the current value of `i`, not the value when you define the lambda. Using default value of lambda, i.e. `lambda i=i:...`, the argument `i` will be assigned the value of `i` at that moment which is what you expect. – acw1668 Feb 05 '20 at 08:53

0 Answers0