Home > database >  Is there a way to have a regular class modify a Tkinter class?
Is there a way to have a regular class modify a Tkinter class?

Time:07-15

I know that you can have a Tkinter class access another Tkinter class (How to access variables from different classes in tkinter?) But im looking for a way to have a regular class, to call functions / modify attributes from a Tkinter class.

import tkinter as tk
import tkinter.ttk as ttk

class Music:
    song = "Song!"
    album = "Album!"
    def change_album(self):
        self.album = "new album!"


everyones_music = Music()


class Main(tk.Tk):
    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.geometry("1000x750 125 100")
        self.configure(bg="#272c34")
        self.resizable(False, False)
        self.frames = {}
        main_page_frame = tk.Frame(self)
        main_page_frame.pack(side="top", fill="both", expand=True)
        main_page_frame.grid_rowconfigure(0, weight=1)
        main_page_frame.grid_columnconfigure(0, weight=1)
        self.frames = {}
        for F in (main_page, second_page):
            frame = F(main_page_frame, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")
        self.show_frame(main_page)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.event_generate("<<ShowFrame>>")
        frame.tkraise()

    def get_page(self, page_class):
        return self.frames[page_class]

class main_page(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller
        self.configure(bg="#272c34")
        y = tk.Label(self, text="main_page!")
        x = tk.Button(self, text="View second:", command=lambda: self.controller.show_frame(second_page))
        x.place(x=100, y=100)
        y.place(x=250, y=100)
        new_button = tk.Button(self, text='Change the variable', command=lambda: everyones_music.change_album())
        new_button.place(x=100, y=150)

class second_page(tk.Frame):
    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.configure(bg="#272c34")
        self.me = tk.Label(self, text=everyones_music.album)
        self.me.place(x=200, y=100)
        self.but = tk.Button(self, text="UPdate ??", command=self.update_is)
        self.but.place(x=100, y=100)

    def update_is(self):
        print(everyones_music.album)
        self.me.configure(text=everyones_music.album)




main_app = Main()
main_app.mainloop()

Essentially, I want the instance of class Music to be able to modify, or call functions in a Tkinter class. Specifically, function "change_album" should have like:

    def change_album(self):
        self.album = "new album!
        second_page.update_is()

Do I want an instance for each page? Does the class Music need to have a way to access the controller and modify properties from there? It is important that there is only one instance of Music, as required for the program.

CodePudding user response:

There's nothing preventing a tkinter class from modifying any other object. Your code is successfully modifying the object. The problem isn't that you can't update the object, the problem is that your other page isn't being notified that the object has changed.

There are many ways to solve this. One solution is to have the function that calls change_album to generate an event. Then, modify your second window to listen for that event. Personally, I would add a change_album method to the controller, and then the controller can send the event to each page. Then, every page that needs to know when the album changes can subscribe to the event.

The solution might look like the following example.

class Main(tk.Tk):
    ...
    def change_album(self):
        everyones_music.change_album()
        for page in self.frames.values():
            page.event_generate("<<AlbumChanged>>")

class main_page(tk.Frame):
    def __init__(self, parent, controller):
        ...
        new_button = tk.Button(self, text='Change the variable', command=self.controller.change_album)
        ...

class second_page(tk.Frame):
    def __init__(self, parent, controller):
        ...
        self.bind("<<AlbumChanged>>", self._album_changed)

    def _album_changed(self, event):
        self.me.configure(text=everyones_music.album)

  • Related