1

I'm building a python app using tkinter(python 3.9.7) and I'm struggling to make a functionnal sidebar navigation. As you'll see in the code below i use a class inheriting from tk.Tk for the main windows, inside of that I instantiate an instance of a specific class inheriting from tk.Frame for each page i need. Inside thoses objects I instantiate an instance of the SideBar class inheriting from tk.Frame too.

Since I switched to a specific class for the sidebar (before that, i duplicated the sidebar code inside each page class and it worked but it was not clean and a lot of code repetition.) the navigation is broken, every button raises the last pages.

The correct Page is Raised at startup but every button raises the last page (SyncPage).

I think the lambda for my buttons is wrong, but i can't figure why and how to correct it.

    class Interface(tk.Tk):
        def __init__(self):
            super().__init__(className="Serbitar")
            self.attributes("-type", "utility")
            self.width = 600
            self.height = 800
            self.geometry(str(self.width) + "x" + str(self.height))
            self.title = "Serbitar" + str(self.version)
            self.yt_data = Yt_Data()
            # Top frame pour accueillir la barre de titre
            self.top_frame = tk.Frame(self, relief="groove", bd=2)
            # Content Frame est un container pour acceuillir
            # les différentes frames en fonction du contenu
            self.content_frame = tk.Frame(self, relief="flat", bd=2)
            self.content_frame.grid_rowconfigure(0, weight=1)
            self.content_frame.grid_columnconfigure(0, weight=1)
            self.content_pages = {}
            for P in (StartPage, YTPage, CalibrePage, TaskPage, ExportPage, SyncPage):
                page = P(self.content_frame, self)
                self.content_pages[P] = page
                page.grid(row=0, column=0, sticky="nsew")
            # Elements de la Barre de titre
            self.l_titre = tk.Label(
                self.top_frame, text="Welcome to Serbitar v" + self.version, padx=30
            )
            self.b_exit = tk.Button(self.top_frame, text="X", command=self.quit)
            # Placement des éléments de la barre de titre
            self.l_titre.pack(side="left", fill="both", expand=True)
            self.b_exit.pack(side="right", fill="y")
            # Placement des frames globales
            self.top_frame.pack(side=tk.TOP, expand=True, fill="x")
            self.content_frame.pack(side=tk.BOTTOM, expand=True, fill="both")

            self.show_page(StartPage)

        def show_page(self, cont):
            page = self.content_pages[cont]
            print(self.content_pages[cont])
            page.tkraise()
            self.update()


class StartPage(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.ctl = controller
        self.left_fsp = SideBar(self, self.ctl, 0)
        self.main_f = tk.Frame(self, relief="flat", bd=2)
        self.txt = tk.Text(self.main_f, width=55, height=20)
        wlcme_txt = "Welcome to serbitar v" + str(__version__) + "\n\n"
        self.txt.insert(tk.END, wlcme_txt)
        self.spacer_m = tk.Frame(
            self.main_f, relief="flat", width=470, height=400, bd=0
        )
        self.left_fsp.pack(side="left")
        self.main_f.pack(side="right", expand=True, fill="both")
        self.txt.grid(column=0, row=0)
        self.spacer_m.grid(column=0, row=1, sticky="sew")

class SideBar(tk.Frame):
    def __init__(self, parent, ctl, fid):
        tk.Frame.__init__(self, parent)
        captions = ["Home", "Youtube", "Calibre", "Taskwarrior", "Export", "Sync"]
        page_name = [StartPage, YTPage, CalibrePage, TaskPage, ExportPage, SyncPage]
        self.sb_btton = {}
        for ids in range(6):
            if fid == ids:
                self.page_lbl = tk.Label(self, text=captions[ids], pady=10)
                if ids == 0:
                    self.page_lbl.grid(column=0, row=ids, sticky="new")
                else:
                    self.page_lbl.grid(column=0, row=ids, sticky="ew")
            else:
                print(page_name[ids])
                self.sb_btton[ids] = tk.Button(
                    self,
                    text=captions[ids],
                    command=lambda: ctl.show_page(page_name[ids]),
                )
                if ids == 0:
                    self.sb_btton[ids].grid(column=0, row=ids, sticky="new")
                else:
                    self.sb_btton[ids].grid(column=0, row=ids, sticky="ew")
            self.spacer = tk.Frame(self, relief="flat", width=130, height=600, bd=0)
            self.spacer.grid(column=0, row=6, sticky="sew")

edit: solutions is here, with great explaination thank you : tkinter creating buttons in for loop passing command arguments

command=lambda ids=ids: ctl.show_page(page_name[ids])
Corecaps
  • 23
  • 6

0 Answers0