WinEunuuchs2Unix
WinEunuuchs2Unix

Reputation: 1929

Python can't find tkinter item at coordinates

I have this code:

for item in items:
    print ( "Item: ", item, mycanvas.coords (item) )

print ("Item at 26.0, 188.0 ", mycanvas.find_closest(26.0, 188.0))
print ("Item at 998.0, 594.0 ", mycanvas.find_closest(998.0, 594.0))

When I run it I get:

('Item: ', 1, [985.0, 565.0])
('Item: ', 8, [25.0, 25.0])
('Item: ', 15, [505.0, 25.0])
('Item: ', 28, [1362.0, 31.0])
('Item: ', 35, [1020.0, 119.0])
('Item: ', 42, [1050.0, 583.0])
('Item: ', 49, [25.0, 25.0])
('Item: ', 56, [26.0, 188.0])
('Item: ', 63, [998.0, 594.0])
('Item: ', 70, [1152.0, 38.0])
('Item at 26.0, 188.0 ', (57,))
('Item at 998.0, 594.0 ', (64,))

The last two lines should read items 56 and 63 found, respectively.

I have 10 images on the screen and am trying to find out which one is being clicked on. To make matters worse X, Y coordinates are being passed for the screen position and not the canvas position and I'll have to figure out how to convert:

def popup(event):
    x = mycanvas.canvasx(event.x_root)
    y = mycanvas.canvasy(event.y_root)
    print( "Adjusted x, y: ", x, y )
    FoundItem=mycanvas.find_closest(x, y)
    print( "Found Item @ x, y: ", FoundItem, event.x_root, event.y_root )
    FoundTuple=mycanvas.find_overlapping(x, y, x+1, y+1)
    print( "Found Tuple: ", FoundTuple )
    # use coordinates relative to the canvas
#    ItemNdx=items.index(FoundItem)
#    print( "ItemNdx: ", ItemNdx )
    menu.tk_popup(event.x_root, event.y_root)

In Python's Tkinter what's the easiest way to find out which image (item/ tag ID) a user has clicked on?


Monitor image with Window Images

To give an idea of what the canvas looks like:

wman2 edp-1-1.png

This is the portion for one of the three monitors eDP-1-1. Giving worst case scenario there are four windows open:

Window stacking order isn't perfect yet because wmctrl is used to get all open windows on desktop without any sorting by stacking order yet.

So the user would click closest to the top left corner of the image they want to select. User could also click empty monitor area not covered by a window to select the monitor image. - Firefox browser with this website

Tag current is also one off

I put in this code:

tag_current=event.widget.find_withtag("current")
print ("tag_current: ", tag_current)

And the results were this:

('Item: ', 1, [985.0, 565.0])
('Item: ', 8, [25.0, 25.0])
('Item: ', 15, [505.0, 25.0])
('Item: ', 28, [1362.0, 31.0])
('Item: ', 35, [949.0, 167.0])
('Item: ', 42, [1050.0, 583.0])
('Item: ', 49, [83.0, 52.0])
('Item: ', 56, [26.0, 188.0])
('Item: ', 63, [998.0, 594.0])
('Item: ', 70, [25.0, 25.0])
('Item: ', 77, [1091.0, 644.0])
('Item at 26.0, 188.0 ', (70,))
('Item at 998.0, 594.0 ', (64,))
('tag_current: ', (41,))

tag_current should be 42 but is being reported as 41.

Much the same problem where 63 is reported as 64 and 56 is being reported as 70 (previously reported as 57 last time job was run).


12 hour update

12 hours later and I'm getting closer. It is necessary to convert from Window coordinates (entire desktop of three monitors) to canvas coordinates (one Python program on one of the monitors):

def popup(event):
    global FoundItem, MouseXY
    x = mycanvas.canvasx(event.x)
    y = mycanvas.canvasy(event.y)
    MouseXY=(x, y)
    print( "Adjusted x, y: ", x, y )
    FoundItem=mycanvas.find_closest(x, y)

Hopefully by tonight problem will be solved...

Upvotes: 0

Views: 1014

Answers (2)

WinEunuuchs2Unix
WinEunuuchs2Unix

Reputation: 1929

Here is the final solution to make it work:

def popup(event):
    global FoundItem
#    print( "Root x, y: ", event.x_root, event.y_root )
#    print( "event x, y: ", event.x, event.y )
    FoundItem=mycanvas.find_closest(event.x, event.y)
    menu.tk_popup(event.x_root, event.y_root)

You can remove the comments (# character) to see the x,y coordinates in your terminal.

  • The .tk_popup or .post command expects Screen Desktop coordinates: (event.x_root, event.y_root)
  • The .find_closest command expects Canvas coordinates: (event.x, event.y)

Upvotes: 0

Bryan Oakley
Bryan Oakley

Reputation: 385870

The way to find out "which image (tag/ tag ID) a user has clicked on" is to use the tag current. The canonical tcl/tk documentation says the following about the current tag:

The tag current is managed automatically by Tk; it applies to the current item, which is the topmost item whose drawn area covers the position of the mouse cursor (different item types interpret this in varying ways; see the individual item type documentation for details). If the mouse is not in the canvas widget or is not over an item, then no item has the current tag.

Here is a contrived example that will print out the tags associated with whatever item you clicked on. Notice that it works even if you scroll the canvas.

import tkinter as tk

def callback(event):
    tags = canvas.itemcget("current", "tags")
    label.configure(text=f"you clicked on {tags}")

root = tk.Tk()
canvas = tk.Canvas(root, width=300, height=300)
label = tk.Label(root)
ysb = tk.Scrollbar(root, orient="vertical", command=canvas.yview)
xsb = tk.Scrollbar(root, orient="horizontal", command=canvas.xview)
canvas.configure(yscrollcommand=ysb.set, xscrollcommand=xsb.set)

root.grid_rowconfigure(0, weight=1)
root.grid_columnconfigure(0, weight=1)

canvas.grid(row=0, column=0, sticky="ew")
xsb.grid(row=1, column=0, sticky="ew")
ysb.grid(row=0, column=1, sticky="ns")
label.grid(row=2, columnspan=2, sticky="ew")

x = 10
y = 10
for color in ("red", "orange", "yellow", "green", "blue", "black", "bisque"):
    canvas.create_rectangle(x, y, x+100, y+100,
                            outline=color, fill=color,
                            tags=(color,)
    )
    x += 50
    y += 50
canvas.configure(scrollregion=canvas.bbox("all"))
canvas.bind("<Button-1>", callback)

root.mainloop()

Upvotes: 1

Related Questions