0

So I've been trying to get into using classes in my tkinter projects, but I seem to have trouble understanding exactly how classes interact. Especially when tkinter is involved. I can accesses variables and values and pass those around, but I can't seem to figure out how to do triggers.

My current problem is with trying to trigger an event from a different class. A simple version of the problem is this:

from tkinter import *

class Area:
    def __init__(self):
        self.can = Canvas(width=100, height=100, bg="green")
        self.can.pack(in_=window)
        self.can.bind("<Button-3>", self.test)
        self.square = self.can.create_rectangle(25, 25, 75, 75)

    def test(self, event):
        self.can.delete("all")

class Trigger:
    def __init__(self):
        self.button = Button(text="click me", command=?)
        self.button.pack(in_=window)

window = Tk()
Area()
Trigger()
window.mainloop()

It creates a green canvas with a square in the middle. When you right click the canvas, the square is removed. I then try to trigger that same behavior from a different class, demonstrated here with a button.

Problem is, I can't for the life of me figure out what to have as a command on the button.

I've tried command=Area.test, but then I get "

TypeError: test() missing 2 required positional arguments: 'self' and 'event'"

I've tried command=Area.test(Area, "event") and command=Area.test(self, "event"), but they return:

AttributeError: type object 'Area' has no attribute 'can'

and

AttributeError: type object 'Area' has no attribute 'can'

I also tried Area().test("event), which gave no error but gave me 2 instances of the canvas, one with the square and one without. The button did nothing then.

Looked into inheritance, so I tried that by putting Area as inheritance on the Trigger class, then do command=self.test("event") But then got:

AttributeError: 'Trigger' object has no attribute 'can'

So I'm out of ideas.. Am I doing the __init__part wrong?

1 Answer 1

1

First, if you want to use a function both as a target of an event and as the value for a command attribute, you should make the event argument optional. You can do that by giving it a default value of None:

def test(self, event=None):
    self.can.delete("all")

Second, the Trigger object needs to be given the instance of the Area object so that it can call methods on that object. There are several ways to do this, but the most straight-forward is to pass it in when creating the object. This means you need to modify Trigger.__init__ to accept the parameter, and then you need to pass it in when creating the object.

This is how to modify the __init__ method:

class Trigger:
    def __init__(self, area):
        self.button = Button(text="click me", command=area.test)
        self.button.pack(in_=window)

This is how to pass the Area object to the Trigger object:

area=Area()
Trigger(area)
Sign up to request clarification or add additional context in comments.

1 Comment

That worked wonderfully, thanks! Do I have to first state the area=Area() though, wouldn't Trigger(Area()) be the same thing?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.