Python/Tkinter - Identify object on click

拟墨画扇 提交于 2019-12-11 05:13:36

问题


I am trying to create a program that changes the object colour on click from white to black or from white to black depending of the previous colour. I would want the program change the colour only if the object is a rectangle. How can I make the this happen?

Here is my code:

import tkinter as tk

root = tk.Tk()

cv = tk.Canvas(root, height=800, width=800)
cv.pack()

def onclick(event):
    item = cv.find_closest(event.x, event.y)

    current_color = cv.itemcget(item, 'fill')

    if current_color == 'black':
        cv.itemconfig(item, fill='white')

    else:
        cv.itemconfig(item, fill='black')


cv.bind('<Button-1>', onclick)

cv.create_line(50, 50, 60, 60, width=2)

cv. create_rectangle(80, 80, 100, 100)

root.mainloop()

In this code the program changes the fill colour for any object. I would want it to change it only for rectangles.

Thanks for the help.


回答1:


Here are three common solutions to this problem:

Using the item type

You can ask the canvas for the type of the object:

item_type = cv.type(item)
if item_type == "rectangle":
    # this item is a rectangle
else:
    # this item is NOT a rectangle

Using tags

Another solution is to give each item one or more tags. You can then query the tags for the current item.

First, include one or more tags on the items you want to be clickable:

cv. create_rectangle(80, 80, 100, 100, tags=("clickable",))

Next, check for the tags on the item you're curious about, and check to see if your tag is in the set of tags for that item:

tags = cv.itemcget(item, "tags")
if "clickable" in tags:
    # this item has the "clickable" tag
else:
    # this item does NOT have the "clickable" tag

Create bindings on tags

A third option is to attach the bindings to the tags rather than the canvas as a whole. When you do this, your function will only be called when you click on item with the given tag, eliminating the need to do any sort of runtime check:

cv.tag_bind("clickable", "<1>", onclick)



回答2:


The solution of BPL is fine. Here is another solution that doesn't require any global variable. There's a system of tags in Tkinter which could be compared with "class" from HTML/CSS. It enables us to associate a list of tags to a graphic object. See item specifiers.

Here is how it would be:

import tkinter as tk


def onclick(event):
    global rectangles
    item = cv.find_closest(event.x, event.y)
    if 'rect' in cv.gettags(item):
        current_color = cv.itemcget(item, 'fill')

        if current_color == 'black':
            cv.itemconfig(item, fill='white')
        else:
            cv.itemconfig(item, fill='black')

rectangles = []

root = tk.Tk()
cv = tk.Canvas(root, height=800, width=800)
cv.pack()
cv.bind('<Button-1>', onclick)

id_a = cv.create_line(50, 50, 60, 60, width=2)
id_b = cv.create_rectangle(80, 80, 100, 100, tags=('rect'))

root.mainloop()

I think it's a bit more object oriented in some way. ;)




回答3:


What about this solution:

import tkinter as tk


def onclick(event):
    global rectangles
    item = cv.find_closest(event.x, event.y)
    if item[0] in rectangles:
        current_color = cv.itemcget(item, 'fill')

        if current_color == 'black':
            cv.itemconfig(item, fill='white')
        else:
            cv.itemconfig(item, fill='black')

rectangles = []

root = tk.Tk()
cv = tk.Canvas(root, height=800, width=800)
cv.pack()
cv.bind('<Button-1>', onclick)

id_a = cv.create_line(50, 50, 60, 60, width=2)
id_b = cv.create_rectangle(80, 80, 100, 100)
rectangles.append(id_b)

root.mainloop()

The main idea of this is you add the items id you want to change color to a global array (global variables are discouraged though). Then when you click with the mouse, the itemcget function will give you the id from the closest item, so you need to check whether this id is inside of the array of your rectangle items.




回答4:


Based on this accepted answer you need to tag_bind your rectangles. Also, you should be assigning IDs to each object you create. If you need to do this repeatedly, you can wrap the process in a loop or functions, but the base theory won't change. GL with tkinter!



来源:https://stackoverflow.com/questions/38982313/python-tkinter-identify-object-on-click

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!