pythonfunctionclasstkinterframe

How to call a function from another frame in tkinter witheout getting an AttributeError: object has no attribute


Hello everyone I am kinda new to python and Tkinter I start it few month ago. I'm currently working on tkinter app for my work. this is a simple app that got 3 pages one for the home page, another is a form to send entry to a database and the last one to change the entry sended in DB.

I try to add a night mode to the app to change the GUI by swapping themes. I make a function per page and it work for each pages but now I'm attempting to make one function that call the other and turn all the app in dark mode but here is the issue. When i call the other function from this new function i got this error: AttributeError: 'PageEdition' object has no attribute 'night_mode'

I will add the code of two page (the home page and the form page) for a better understanding of the problem:

class PageAccueil(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        canvas = Canvas(
            self,
            bg="#FFFFFF",
            height=699,
            width=1300,
            bd=0,
            highlightthickness=0,
            relief="ridge"
        )
        canvas.place(x=0, y=0)
        canvas.create_rectangle(
            0.0,
            0.0,
            1300.0,
            79.0,
            fill="#FA0096",
            outline=""
        )
        canvas.create_rectangle(
            0.0,
            79.0,
            107.0,
            699.0,
            fill="#D9D9D9",
            outline=""
        )
        button_image_1 = PhotoImage(file="assets/frame/button_1.png")
        button_1 = Button(
            image=button_image_1,
            borderwidth=0,
            highlightthickness=0,
            command=lambda: controller.show_frame(PageEdition),
            relief="flat",
            bg="#D9D9D9"
        )
        button_1.image=button_image_1
        button_1.place(
            x=16.0,
            y=110.0,
            width=75.0,
            height=75.0
        )
        button_image_2 = PhotoImage(file="assets/frame/button_2.png")
        button_2 = Button(
            image=button_image_2,
            borderwidth=0,
            highlightthickness=0,
            command=lambda: controller.show_frame(PageRecherche),
            relief="flat",
            bg="#D9D9D9"
        )
        button_2.image=button_image_2
        button_2.place(
            x=16.0,
            y=350.0,
            width=75.0,
            height=75.0
        )

        def swap():
            if button_switch['bg'] == colours_day:
                button_switch.config(image=button_switch_night_img,bg=colours_night,activebackground=colours_night)
                canvas.configure(background=colours_night)
                textAcc.configure(bg=colours_night,fg=colours_day)
                logo_label.configure(image=logo_divia_night,background=colours_night)

            else:
                button_switch.config(image=button_switch_day_img, bg=colours_day, activebackground=colours_day)
                canvas.configure(background=colours_day)
                textAcc.configure(bg=colours_day, fg=colours_night)
                logo_label.configure(image=logo_divia_day, background=colours_day)

        colours_day='#FFFFFF'
        colours_night='#2b2a33'

        logo_divia_day = tk.PhotoImage(file='assets/frame/image_1.png')
        logo_divia_night = tk.PhotoImage(file='assets/frame/logodivia_dark.png')
        logo_label = Label(self, image=logo_divia_day, borderwidth=0, background=colours_day)
        logo_label.place(x=1100, y=600)



        def dark_on_off():
            swap()
            page_instance = self.controller.get_page(PageEdition)
            page_instance.night_mode()
class PageEdition(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        scrollbar=Scrollbar(self,orient="vertical",bg="grey")
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        canvas = Canvas(
            self,
            bg="#FFFFFF",
            height=699,
            width=1300,
            bd=0,
            highlightthickness=0,
            relief="ridge"
        )
        canvas.place(x=0, y=0)
        canvas.create_rectangle(
            0.0,
            0.0,
            1300.0,
            79.0,
            fill="#FA0096",
            outline=""
        )
        canvas.create_rectangle(
            0.0,
            79.0,
            107.0,
            699.0,
            fill="#D9D9D9",
            outline=""
        )
        canvas.create_text(
            410.0,
            0.0,
            anchor="nw",
            text="Edition des données",
            fill="#FFFFFF",
            font=("Inter", 64 * -1)
        )

        def on_validate(p):
            if p.isdigit() or p=="":
                return True
            else:
                return False

        vcmd = (self.register(on_validate), '%P')



        colours_night = '#2b2a33'
        colours_day = '#FFFFFF'

        def change_text_color_to_white(widget):
            if canvas['background'] == colours_night:
                if isinstance(widget, tk.Label):
                    widget.config(fg=colours_day, background=colours_night)
                if isinstance(widget, tk.Button):
                    widget.config(background=colours_night)
                if isinstance(widget, tk.Radiobutton):
                    widget.config(fg=colours_day, background=colours_night)
                if isinstance(widget, tk.Checkbutton):
                    widget.config(fg=colours_day, background=colours_night)
            else:
                if isinstance(widget, tk.Label):
                    widget.config(fg=colours_night, background=colours_day)
                if isinstance(widget, tk.Button):
                    widget.config(background=colours_day)
                if isinstance(widget, tk.Radiobutton):
                    widget.config(fg=colours_night, background=colours_day)
                if isinstance(widget,tk.Checkbutton):
                    widget.config(fg=colours_night, background=colours_day)

        def night_mode(self):
            if canvas['background'] == colours_day:
                canvas.configure(background=colours_night)
                children = self.winfo_children()
                for child in children:
                    change_text_color_to_white(child)


            else:
                canvas.configure(background=colours_day)
                children = self.winfo_children()
                for child in children:
                    change_text_color_to_white(child)

        testbtn = Button(
            self,
            text="il vas faire tout noir",
            borderwidth=0,
            highlightthickness=0,
            command=lambda:night_mode(self),
            relief="flat"
        )
        testbtn.pack()

The error occured when calling the function dark_on_off()it does execute the function swap() but when the function calls page_instance.night_mode() i got this error: AttributeError: 'PageEdition' object has no attribute 'night_mode'

I searched on the web for a moment before asking here, i tried to change the way i make instance of my other class but i dont get much success, i tried to add the function on the initialisation parameters of the class but it didnt work and recently i try to defined the function out of the def__init__() but it didnt work at all. I saw post that are lookalike mine but the answers didnt match my case it is why I'am asking for help.

If someone have an idea to solve this, I'm grateful for whatever support you can offer!

Thank you in advance

Nelson


Solution

  • Thanks to matszwecja's help i managed to find a way to reorganize my code and I defined my night_mode function outside my function init in order to call it from my home page to turn all the application in dark or light mode. Her's the code I changed in the two classes (where i call the function and where i defined it):

    class PageAccueil(tk.Frame):
        def __init__(self, parent, controller):
            def dark_on_off():
                swap()
                pageEd_instance = self.controller.get_page(PageEdition)
                pageEd_instance.night_mode()
    
    class PageEdition(tk.Frame):
        colours_night = '#2b2a33'
        colours_day = '#FFFFFF'
        
        def __init__(self, parent, controller):
        
        def change_text_color_to_white(self, widget):
            if self.canvas['background'] == self.colours_night:
                if isinstance(widget, tk.Label):
                    widget.config(fg= self.colours_day, background= self.colours_night)
                if isinstance(widget, tk.Button):
                    widget.config(background= self.colours_night)
                if isinstance(widget, tk.Radiobutton):
                    widget.config(fg= self.colours_day, background= self.colours_night)
                if isinstance(widget, tk.Checkbutton):
                    widget.config(fg= self.colours_day, background= self.colours_night)
            else:
                if isinstance(widget, tk.Label):
                    widget.config(fg=  self.colours_night, background=  self.colours_day)
                if isinstance(widget, tk.Button):
                    widget.config(background= self.colours_day)
                if isinstance(widget, tk.Radiobutton):
                    widget.config(fg=  self.colours_night, background=  self.colours_day)
                if isinstance(widget, tk.Checkbutton):
                    widget.config(fg =  self.colours_night, background=  self.colours_day)
        def night_mode(self):
            if self.canvas['background'] == self.colours_day:
                self.canvas.configure(background = self.colours_night)
                children = self.winfo_children()
                for child in children:
                    self.change_text_color_to_white(child)
            else:
                self.canvas.configure(background = self.colours_day)
                children = self.winfo_children()
                for child in children:
                    self.change_text_color_to_white(child)
    

    Thank you again matszwecja for help