0

I am trying to make the GUI for a logic circuit simulator. My idea is that when the picture/icon for a gate is clicked, the object that picture/icon belongs to becomes selected and saved to be used for a later function that links two different gates together. However, the issue lies in that there seems to be no way to bind a mouse event to a picture in tkinter the same way you would with a button.

When running the program, an attribute error is thrown from the line

self.root.orIcon.tag_bind(orGateObject.getIcon(), '<Button-1>', lambda: self.makeSelected(orGateObject.getIcon()))

AttributeError: 'PhotoImage' object has no attribute 'tag_bind'

The same error is thrown when using .bind instead of .tag_bind as well.

from tkinter import *

class orGate:
    def __init__(self):
        self.filePath = 'Project programs/gate pictures/or.png'
        self.icon = None

    def getFilePath(self):
        return self.filePath

    def makeIconBelongTo(self, icon):
        self.icon = icon

    def getIcon(self):
        return self.icon

class Window:
    def __init__(self):
        self.root = Tk() # root widget (window)
        self.root.title("Logic Circuit Simulator")

        # tool section
        self.toolFrame = LabelFrame(self.root, text="Tools", width=100, height=500)
        self.toolFrame.config(bg="lightgrey")
        self.toolFrame.grid(row=0, column=0, padx=5, pady=5)
        
        #gates section within tool section
        self.gatesLabelFrame = LabelFrame(self.toolFrame, text="Gates", width=5, height=1, borderwidth=1, relief="ridge")
        self.gatesLabelFrame.grid(row=0, column=0, padx=5, pady=10)

        # workFrame 
        self.workFrame = Frame(self.root, width=1000, height=550)
        self.workFrame.grid(row=0, column=1, padx=5, pady=5)

        #actual visual frame (the circuit goes in here) within workFrame
        self.visualFrame = LabelFrame(self.workFrame, text="Workspace", width=1000, height=500)
        self.visualFrame.config(bg="lightgrey")
        self.visualFrame.grid(row=1, column=0, padx=5, pady=5)

        #options bar frame 
        self.optionsLabelFrame = LabelFrame(self.workFrame, text="Options", width= 1000, height=30)
        self.optionsLabelFrame.config(bg="lightgrey")
        self.optionsLabelFrame.grid(row=0, column=0, padx=5, pady=5)
    
        #canvas (workspace) within visual frame
        self.workspace = Canvas(self.visualFrame, bg="lightgrey", width=1000, height=500)
        self.workspace.grid(row=0, column=0, padx=5, pady=5)
    
        #buttons
        orButton = Button(self.gatesLabelFrame, text="OR", command=lambda:self.createOrGate(), relief="groove")

        orButton.grid(row=2, column=0, padx=5, pady=5)

        self.gatesAndIcons = []

        self.selectedObject = None


    def runWindow(self):
        return self.root.mainloop()
    

    def makeSelected(self, icon):
        for i in self.gatesAndIcons:
            if i[1] == icon:
                self.selectedObject = i[0]
                print("selection made") # check if selection was made


    def createOrGate(self):
        #instantiate OR gate
        orGateObject = orGate()
        
        orIcon = PhotoImage(file=orGateObject.getFilePath())
        self.root.orIcon = orIcon  # to prevent the image garbage collected.

        orGateObject.makeIconBelongTo(self.root.orIcon) # making the icon an attribute of the or gate object

        self.workspace.create_image(500, 250, image=orGateObject.getIcon())

        self.gatesAndIcons.append([orGateObject, orGateObject.getIcon()]) # create object and icon pair so when icon is clicked on the canvas, the object it belongs to becomes the selected item

        self.root.orIcon.tag_bind(orGateObject.getIcon(), '<Button-1>', lambda: self.makeSelected(orGateObject.getIcon())) # the issue here is the binding of the click event to the icon
        print(self.selectedObject)
        

Window = Window()
Window.runWindow()
James Z
  • 12,209
  • 10
  • 24
  • 44
retsaot
  • 1
  • 1
  • 1
    `.tag_bind()` is something you would call on the containing Canvas, *not* the items that you've added to the Canvas. – jasonharper Feb 07 '23 at 20:23
  • What can I do for items that I have added to the Canvas then? – retsaot Feb 07 '23 at 20:24
  • You pass them as the first parameter to `.tag_bind()`. Note that I'm talking about the return value from `.create_image()` and similar Canvas methods, the PhotoImage object itself is not a usable identifier (since there can be any number of Canvas items sharing the same image). – jasonharper Feb 07 '23 at 20:27
  • By using self.workspace(self.root.orIcon, '', lambda: self.makeSelected(orGateObject.getIcon())) a new error is returned TypeError: 'Canvas' object is not callable – retsaot Feb 07 '23 at 20:41
  • Does this answer your question? [How to bind events to Canvas items?](https://stackoverflow.com/questions/2786877/how-to-bind-events-to-canvas-items) – relent95 Feb 08 '23 at 02:12

0 Answers0