1

This is my code:

class TimeFrame(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

        self.text = tk.Text(self, height=10, width=110)
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview)
        self.text.configure(yscrollcommand=self.vsb.set)
        self.vsb.pack(side="right", fill="y")
        self.text.pack(side="left", fill="both", expand=True)

    def add_timestamp(self):
        self.text.insert("end", time.ctime() + "\n")
        self.text.see("end")
        self.after(1000, self.add_timestamp)


class ButtonFrame(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

        self.button = tk.Button(self, text="Start Time", command=self.start_time)
        self.button.pack()

    def start_time(self):
        TimeFrame.add_timestamp()
        


if __name__ == "__main__":
    root = tk.Tk()
    time_frame = TimeFrame(root)
    time_frame.pack(fill="both", expand=True, padx=10, pady=20)
    button_frame = ButtonFrame(root)
    button_frame.pack(fill="both", expand=True, pady=(0, 20))
    root.mainloop()

I want that the add_timestamp() function runs when the button is clicked.

Without an argument in TimeFrame.add_timestamp() I get an error saying missing argument "self". What do I need to write as an argument there that it is working properly?

1 Answers1

2

Note that TimeFrame.add_timestamp(self) is actually an instance method. That means, that you cannot call it without providing a specific instance, which is then passed as self.

Imagine you would create two TimeFrames a = TimeFrame(root) and b = TimeFrame(root), then you would need to call add_timestamp for one of them using either a.add_timestamp() or b.add_timestamp().

So in your case, you already have a TimeFrame instance (called time_frame). Now what you need, is a reference from ButtonFrame to TimeFrame, so that each ButtonFrame can refer to a specific TimeFrame instance.

As a simple solution, you could pass time_frame to button_frame on creation and store it as an attribute. You can then call add_timestamp on that specific instance (not tested):

class TimeFrame(tk.Frame):
    def __init__(self, *args, **kwargs):
        tk.Frame.__init__(self, *args, **kwargs)

        self.text = tk.Text(self, height=10, width=110)
        self.vsb = tk.Scrollbar(self, orient="vertical", command=self.text.yview)
        self.text.configure(yscrollcommand=self.vsb.set)
        self.vsb.pack(side="right", fill="y")
        self.text.pack(side="left", fill="both", expand=True)

    def add_timestamp(self):
        self.text.insert("end", time.ctime() + "\n")
        self.text.see("end")
        self.after(1000, self.add_timestamp)


class ButtonFrame(tk.Frame):
    def __init__(self, root, time_frame, *args, **kwargs):
        tk.Frame.__init__(self, root, *args, **kwargs)

        self.time_frame = time_frame
        self.button = tk.Button(self, text="Start Time", command=self.start_time)
        self.button.pack()

    def start_time(self):
        self.time_frame.add_timestamp()
        


if __name__ == "__main__":
    root = tk.Tk()
    time_frame = TimeFrame(root)
    time_frame.pack(fill="both", expand=True, padx=10, pady=20)
    button_frame = ButtonFrame(root, time_frame)
    button_frame.pack(fill="both", expand=True, pady=(0, 20))
    root.mainloop()

Take a look at this answer for a better explanation on the difference between class and instance methods.

  • When I run this code I get AttributeError: '_tkinter.tkapp' object has no attribute 'add_timestamp'. I don't understand the linked answer either :/. – samuelhertrich Jun 30 '21 at 13:06
  • Ah, I see. Try again, if it still does not work I‘ll have a look once I‘m back at a computer. – Dominik Berse Jun 30 '21 at 13:22