Posts: 144
Threads: 41
Joined: Jun 2020
Jul-17-2022, 07:43 AM
(This post was last modified: Jul-17-2022, 07:43 AM by hobbyist.)
So, the idea is that I try to load an image, navigate Up, Down, Right, Left with the arrows and each time I press the mouse button to get the image's coordinates, not the canvas' coordinates. I use code from here: https://stackoverflow.com/questions/5563...s-of-the-s and from here: https://stackoverflow.com/questions/3366...arrow-keys I face difficulties in achieving that... more specifically none of the keys Up, Down, Left, Right works and also when I press the mouse button nothing happens... My code is depicted below...Do you have any idea what I wrote wrong?
print("A")
import tkinter as tk
print("B")
from PIL import Image, ImageTk
print("C")
#class Example(tk.Frame):
#print("D")
##def __init__(self, parent):
##print("0")
##tk.Frame.__init__(self, parent)
print("1")
WIDTH, HEIGHT = 900, 900
print("2")
topx, topy, botx, boty = 0, 0, 0, 0
print("3")
rect_id = None
print("4")
path = "test_image.jpg"
print("5")
def get_mouse_posn(event):
print("6")
topx, topy = event.x, event.y
print("7")
print("topx = ", topx)
print("8")
print("topy = ", topy)
print("9")
def update_sel_rect(event):
print("10")
botx, boty = event.x, event.y
print("11")
canvas.coords(rect_id, topx, topy, botx, boty) # Update selection rect.
print("12")
print("botx = ", botx)
print("13")
print("boty = ", boty)
window = tk.Tk()
print("14")
window.title("Select Area")
print("15")
window.geometry('%sx%s' % (WIDTH, HEIGHT))
print("16")
window.configure(background='grey')
print("17")
img = ImageTk.PhotoImage(Image.open(path))
print("18")
canvas = tk.Canvas(window, width=img.width(), height=img.height(),
borderwidth=0, highlightthickness=0)
print("19")
canvas.pack(expand=True)
print("20")
canvas.img = img # Keep reference in case this code is put into a function.
print("21")
canvas.create_image(0, 0, image=img, anchor=tk.NW)
print("22")
# Create selection rectangle (invisible since corner points are equal).
rect_id = canvas.create_rectangle(topx, topy, topx, topy,
dash=(2,2), fill='', outline='white')
print("23")
canvas = tk.Canvas(background="bisque")
print("24")
vsb = tk.Scrollbar(orient="vertical", command=canvas.yview)
print("25")
hsb = tk.Scrollbar(orient="horizontal", command=canvas.xview)
print("26")
canvas.configure(xscrollcommand=hsb.set, yscrollcommand=vsb.set)
print("27")
#canvas.grid(row=0, column=0, sticky="nsew")
print("28")
#vsb.grid(row=0, column=1, sticky="ns")
print("29")
#hsb.grid(row=1, column=0, sticky="ew")
print("30")
canvas.configure(scrollregion = canvas.bbox("all"))
print("31")
canvas.bind("<1>", lambda event: canvas.focus_set())
print("32")
canvas.bind("<Left>", lambda event: canvas.xview_scroll(-1, "units"))
print("33")
canvas.bind("<Right>", lambda event: canvas.xview_scroll( 1, "units"))
print("34")
canvas.bind("<Up>", lambda event: canvas.yview_scroll(-1, "units"))
print("35")
canvas.bind("<Down>", lambda event: canvas.yview_scroll( 1, "units"))
print("36")
canvas.focus_set()
print("37")
canvas.bind('<Button-1>', get_mouse_posn)
print("38")
canvas.bind('<B1-Motion>', update_sel_rect)
print("39")
window.mainloop()
Posts: 144
Threads: 41
Joined: Jun 2020
I have posted code, links, prints inside the code, I have showed effort. Can somebody help me here?
Posts: 12,041
Threads: 487
Joined: Sep 2016
Jul-18-2022, 10:33 PM
(This post was last modified: Jul-18-2022, 10:33 PM by Larz60+.)
Edited 6:32 EDT
In the future, please remove annoying print statements before posting.
Added bind statement after creating canvas, also renamed 'path' to 'imagefile'
import tkinter as tk
from PIL import Image, ImageTk
import os
os.chdir(os.path.abspath(os.path.dirname(__file__)))
WIDTH, HEIGHT = 900, 900
topx, topy, botx, boty = 0, 0, 0, 0
rect_id = None
imagefile = "test_image.jpg"
def get_mouse_posn(event):
topx, topy = event.x, event.y
print("topx = ", topx)
print("topy = ", topy)
def update_sel_rect(event):
botx, boty = event.x, event.y
canvas.coords(rect_id, topx, topy, botx, boty) # Update selection rect.
print("botx = ", botx)
print("boty = ", boty)
window = tk.Tk()
window.title("Select Area")
window.geometry('%sx%s' % (WIDTH, HEIGHT))
window.configure(background='grey')
img = ImageTk.PhotoImage(Image.open(imagefile))
canvas = tk.Canvas(window, width=img.width(), height=img.height(),
borderwidth=0, highlightthickness=0)
canvas.pack(expand=True)
canvas.img = img # Keep reference in case this code is put into a function.
canvas.create_image(0, 0, image=img, anchor=tk.NW)
canvas.bind("<Button 1>", get_mouse_posn)
# Create selection rectangle (invisible since corner points are equal).
rect_id = canvas.create_rectangle(topx, topy, topx, topy,
dash=(2,2), fill='', outline='white')
canvas = tk.Canvas(background="bisque")
vsb = tk.Scrollbar(orient="vertical", command=canvas.yview)
hsb = tk.Scrollbar(orient="horizontal", command=canvas.xview)
canvas.configure(xscrollcommand=hsb.set, yscrollcommand=vsb.set)
#canvas.grid(row=0, column=0, sticky="nsew")
#vsb.grid(row=0, column=1, sticky="ns")
#hsb.grid(row=1, column=0, sticky="ew")
canvas.configure(scrollregion = canvas.bbox("all"))
canvas.bind("<1>", lambda event: canvas.focus_set())
canvas.bind("<Left>", lambda event: canvas.xview_scroll(-1, "units"))
canvas.bind("<Right>", lambda event: canvas.xview_scroll( 1, "units"))
canvas.bind("<Up>", lambda event: canvas.yview_scroll(-1, "units"))
canvas.bind("<Down>", lambda event: canvas.yview_scroll( 1, "units"))
canvas.focus_set()
canvas.bind('<Button-1>', get_mouse_posn)
canvas.bind('<B1-Motion>', update_sel_rect)
window.mainloop()
Posts: 144
Threads: 41
Joined: Jun 2020
@ Larz60+ Thank you so much for your time!!! The arrows do not work...what should I change?
Posts: 12,041
Threads: 487
Joined: Sep 2016
hobbyist Wrote:The arrows do not work Very vague, be more specific.
Posts: 144
Threads: 41
Joined: Jun 2020
@ Larz60+ I press Right, Left, Up, Down keys on the keyboard, the image is not moving...inside the canvas...
Posts: 6,817
Threads: 20
Joined: Feb 2020
Jul-19-2022, 08:45 PM
(This post was last modified: Jul-19-2022, 08:45 PM by deanhystad.)
In Larz60+'s post there are two canvas objects, one created in line 30 and the other in line 42. I think that was a mistake. Ends up that events are bound to different canvas widgets, and some are bound to the canvas that never gets focus. It would probably be better to have the canvas take focus when you click it
I think the answer to the original post question is that you need to find the location of the upper left corner and uses this to offset the mouse event coordinates. Look at get_mouse_posn() and update_sel_rect() in the code below.
import tkinter as tk
from PIL import Image, ImageTk
WIDTH, HEIGHT = 900, 900
sel_rect = [0, 0, 0, 0]
imagefile = "large_image.jpg"
def get_mouse_posn(event):
print(event.x, canvas.canvasx(0), canvas.canvasx(event.x))
sel_rect[0] = sel_rect[2] = int(canvas.canvasx(event.x))
sel_rect[1] = sel_rect[3] = int(canvas.canvasy(event.y))
canvas.coords(rect_id, *sel_rect)
canvas.focus_set()
def update_sel_rect(event):
sel_rect[2] = int(canvas.canvasx(event.x))
sel_rect[3] = int(canvas.canvasy(event.y))
canvas.coords(rect_id, *sel_rect)
window = tk.Tk()
window.title("Select Area")
window.geometry("%sx%s" % (WIDTH, HEIGHT))
img = ImageTk.PhotoImage(Image.open(imagefile))
canvas = tk.Canvas(window, width=img.width(), height=img.height())
canvas.img = img # Keep reference in case this code is put into a function.
canvas.create_image(0, 0, image=img, anchor=tk.NW)
canvas.bind("<Button 1>", get_mouse_posn)
# Create selection rectangle (invisible since corner points are equal).
rect_id = canvas.create_rectangle(*sel_rect, dash=(2, 2), fill="", outline="white")
vsb = tk.Scrollbar(orient="vertical", command=canvas.yview)
hsb = tk.Scrollbar(orient="horizontal", command=canvas.xview)
canvas.configure(xscrollcommand=hsb.set, yscrollcommand=vsb.set)
canvas.configure(scrollregion=canvas.bbox("all"))
canvas.bind("<Left>", lambda event: canvas.xview_scroll(-1, "units"))
canvas.bind("<Right>", lambda event: canvas.xview_scroll(1, "units"))
canvas.bind("<Up>", lambda event: canvas.yview_scroll(-1, "units"))
canvas.bind("<Down>", lambda event: canvas.yview_scroll(1, "units"))
canvas.bind("<Button-1>", get_mouse_posn)
canvas.bind("<B1-Motion>", update_sel_rect)
canvas.grid(row=0, column=0, sticky="nsew")
hsb.grid(row=1, column=0, sticky="ew")
vsb.grid(row=0, column=1, sticky="ns")
window.rowconfigure(0, weight=1)
window.columnconfigure(0, weight=1)
window.mainloop() Another thing wrong with the original code is topx, topy, botx and boty were used inconsistently. In get_mouse_posn() and update_sel_rect() topx is a local variable, and setting the value does not change the topx value used in update_sel_rect. You could fix this by making all the variables global (using the global keyword in get_mouse_posn), but I decided to put them all together in a list. A better solution is to write this code as a class and make topx, topy, botx and boty attributes.
Posts: 144
Threads: 41
Joined: Jun 2020
@ deanhystad and @ Larz60+ you are awesome!!!!!! Thanks! it works!!
Posts: 144
Threads: 41
Joined: Jun 2020
What modifications I should do in order to print the Upper Left and Lower Right coordinates of the rectangle? I tried something but it does not work..
Posts: 6,817
Threads: 20
Joined: Feb 2020
You could print(sel_rect). It is important to note that the contents of sel_rect are not upper left and lower right, but rather two corners. Depending on how you drag the mouse the upper left corner might be the first corner (first two values) or the second (last two values in the list).
if upper left and lower right are important I would create a class that does all the rectangle selection stuff.
import tkinter as tk
from PIL import Image, ImageTk
WIDTH, HEIGHT = 900, 900
sel_rect = [0, 0, 0, 0]
imagefile = "large_image.jpg"
class RectangleSelection:
"""Class to encompass behavior of Rectangle selection"""
def __init__(self, parent, *args, **kvargs):
self.rect = [0, 0, 0, 0]
self.parent = parent
self.id = parent.create_rectangle(*self.rect, *args, **kvargs)
def start(self, event):
"""Start new rectangle."""
self.rect[0] = self.rect[2] = int(self.parent.canvasx(event.x))
self.rect[1] = self.rect[3] = int(self.parent.canvasy(event.y))
self.parent.coords(self.id, *self.rect)
print(self)
def extend(self, event):
"""Move corner 2"""
self.rect[2] = int(self.parent.canvasx(event.x))
self.rect[3] = int(self.parent.canvasy(event.y))
canvas.coords(self.id, *self.rect)
print(self)
def upper_left(self):
"""Return x, y for upper left corner of rectangle"""
return (min(self.rect[0], self.rect[2]), min(self.rect[1], self.rect[3]))
def lower_right(self):
"""Return x, y for lower right corner of rectangle"""
return (max(self.rect[0], self.rect[2]), max(self.rect[1], self.rect[3]))
def coordinates(self):
return (
min(self.rect[0], self.rect[2]),
min(self.rect[1], self.rect[3]),
max(self.rect[0], self.rect[2]),
max(self.rect[1], self.rect[3]),
)
def __repr__(self):
return f"<Rectangle {self.coordinates()}>"
def button_press(event):
rectangle.start(event)
canvas.focus_set()
window = tk.Tk()
window.title("Select Area")
window.geometry("%sx%s" % (WIDTH, HEIGHT))
img = ImageTk.PhotoImage(Image.open(imagefile))
canvas = tk.Canvas(window, width=img.width(), height=img.height())
canvas.img = img # Keep reference in case this code is put into a function.
canvas.create_image(0, 0, image=img, anchor=tk.NW)
# Create selection rectangle (invisible since corner points are equal).
rectangle = RectangleSelection(canvas, dash=(2, 2), fill="", outline="white")
vsb = tk.Scrollbar(orient="vertical", command=canvas.yview)
hsb = tk.Scrollbar(orient="horizontal", command=canvas.xview)
canvas.configure(xscrollcommand=hsb.set, yscrollcommand=vsb.set)
canvas.configure(scrollregion=canvas.bbox("all"))
canvas.bind("<Left>", lambda event: canvas.xview_scroll(-1, "units"))
canvas.bind("<Right>", lambda event: canvas.xview_scroll(1, "units"))
canvas.bind("<Up>", lambda event: canvas.yview_scroll(-1, "units"))
canvas.bind("<Down>", lambda event: canvas.yview_scroll(1, "units"))
canvas.bind("<Button-1>", button_press)
canvas.bind("<B1-Motion>", rectangle.extend)
canvas.grid(row=0, column=0, sticky="nsew")
hsb.grid(row=1, column=0, sticky="ew")
vsb.grid(row=0, column=1, sticky="ns")
window.rowconfigure(0, weight=1)
window.columnconfigure(0, weight=1)
window.mainloop()
|