我已经拼凑了以下代码(原始源代码here)
我不知道如何使用图像的宽度和高度来驱动应用程序的宽度和高度
我希望应用程序窗口的大小与源图像相同.
代码如下:
import tkinter as tk
from PIL import Image, ImageTk
class MousePositionTracker(tk.Frame):
""" Tkinter Canvas mouse position widget. """
def __init__(self, canvas):
self.canvas = canvas
self.canv_width = self.canvas.cget('width')
self.canv_height = self.canvas.cget('height')
self.reset()
# Create canvas cross-hair lines.
xhair_opts = dict(dash=(3, 2), fill='white', state=tk.HIDDEN)
self.lines = (self.canvas.create_line(0, 0, 0, self.canv_height, **xhair_opts),
self.canvas.create_line(0, 0, self.canv_width, 0, **xhair_opts))
def cur_selection(self):
return (self.start, self.end)
def begin(self, event):
self.hide()
self.start = (event.x, event.y) # Remember position (no drawing).
def update(self, event):
self.end = (event.x, event.y)
self._update(event)
self._command(self.start, (event.x, event.y)) # User callback.
def _update(self, event):
# Update cross-hair lines.
self.canvas.coords(self.lines[0], event.x, 0, event.x, self.canv_height)
self.canvas.coords(self.lines[1], 0, event.y, self.canv_width, event.y)
self.show()
def reset(self):
self.start = self.end = None
def hide(self):
self.canvas.itemconfigure(self.lines[0], state=tk.HIDDEN)
self.canvas.itemconfigure(self.lines[1], state=tk.HIDDEN)
def show(self):
self.canvas.itemconfigure(self.lines[0], state=tk.NORMAL)
self.canvas.itemconfigure(self.lines[1], state=tk.NORMAL)
def autodraw(self, command=lambda *args: None):
"""Setup automatic drawing; supports command option"""
self.reset()
self._command = command
self.canvas.bind("<Button-1>", self.begin)
self.canvas.bind("<B1-Motion>", self.update)
self.canvas.bind("<ButtonRelease-1>", self.quit)
def quit(self, event):
self.hide() # Hide cross-hairs.
self.reset()
class SelectionObject:
""" Widget to display a rectangular area on given canvas defined by two points
representing its diagonal.
"""
def __init__(self, canvas, select_opts):
# Create attributes needed to display selection.
self.canvas = canvas
self.select_opts1 = select_opts
self.width = self.canvas.cget('width')
self.height = self.canvas.cget('height')
# Options for areas outside rectanglar selection.
select_opts1 = self.select_opts1.copy() # Avoid modifying passed argument.
select_opts1.update(state=tk.HIDDEN) # Hide initially.
# Separate options for area inside rectanglar selection.
select_opts2 = dict(dash=(2, 2), fill='', outline='white', state=tk.HIDDEN)
# Initial extrema of inner and outer rectangles.
imin_x, imin_y, imax_x, imax_y = 0, 0, 1, 1
omin_x, omin_y, omax_x, omax_y = 0, 0, self.width, self.height
self.rects = (
# Area *outside* selection (inner) rectangle.
self.canvas.create_rectangle(omin_x, omin_y, omax_x, imin_y, **select_opts1),
self.canvas.create_rectangle(omin_x, imin_y, imin_x, imax_y, **select_opts1),
self.canvas.create_rectangle(imax_x, imin_y, omax_x, imax_y, **select_opts1),
self.canvas.create_rectangle(omin_x, imax_y, omax_x, omax_y, **select_opts1),
# Inner rectangle.
self.canvas.create_rectangle(imin_x, imin_y, imax_x, imax_y, **select_opts2)
)
def update(self, start, end):
# Current extrema of inner and outer rectangles.
imin_x, imin_y, imax_x, imax_y = self._get_coords(start, end)
omin_x, omin_y, omax_x, omax_y = 0, 0, self.width, self.height
# Update coords of all rectangles based on these extrema.
self.canvas.coords(self.rects[0], omin_x, omin_y, omax_x, imin_y),
self.canvas.coords(self.rects[1], omin_x, imin_y, imin_x, imax_y),
self.canvas.coords(self.rects[2], imax_x, imin_y, omax_x, imax_y),
self.canvas.coords(self.rects[3], omin_x, imax_y, omax_x, omax_y),
self.canvas.coords(self.rects[4], imin_x, imin_y, imax_x, imax_y),
for rect in self.rects: # Make sure all are now visible.
self.canvas.itemconfigure(rect, state=tk.NORMAL)
# Update bounding box result
global bounding_box
bounding_box = self._get_coords(start, end)
# # Print result on every change
# print("Bounding Box Result:")
# print(f"Top Left: ({bounding_box[0]}, {bounding_box[1]})")
# print(f"Bottom Right: ({bounding_box[2]}, {bounding_box[3]})\n")
def _get_coords(self, start, end):
""" Determine coords of a polygon defined by the start and
end points one of the diagonals of a rectangular area.
"""
return (min((start[0], end[0])), min((start[1], end[1])),
max((start[0], end[0])), max((start[1], end[1])))
def hide(self):
for rect in self.rects:
self.canvas.itemconfigure(rect, state=tk.HIDDEN)
class Application(tk.Frame):
# Default selection object options.
SELECT_OPTS = dict(dash=(2, 2), stipple='gray25', fill='black',
outline='')
def __init__(self, parent, *args, **kwargs):
super().__init__(parent, *args, **kwargs)
path = "/Users/nathan/Desktop/Books.jpeg"
img = ImageTk.PhotoImage(Image.open(path))
self.canvas = tk.Canvas(root, width=img.width(), height=img.height(),
borderwidth=0, highlightthickness=0)
self.canvas.pack(expand=True)
self.canvas.create_image(0, 0, image=img, anchor=tk.NW)
self.canvas.img = img # Keep reference.
# Create selection object to show current selection boundaries.
self.selection_obj = SelectionObject(self.canvas, self.SELECT_OPTS)
# Callback function to update it given two points of its diagonal.
def on_drag(start, end, **kwarg): # Must accept these arguments.
self.selection_obj.update(start, end)
# Create mouse position tracker that uses the function.
self.posn_tracker = MousePositionTracker(self.canvas)
self.posn_tracker.autodraw(command=on_drag) # Enable callbacks.
# # Create a button to close the application.
# self.close_button = tk.Button(root, text="Close", command=self.close_application)
# self.close_button.pack()
# Bind the Escape and Enter keys to the close_application method.
root.bind("<Escape>", self.close_application)
root.bind("<Return>", self.close_application)
def close_application(self, event=None):
try:
print(bounding_box)
except:
print("None")
root.destroy()
if __name__ == '__main__':
# Set the size and position of the application window.
BACKGROUND = '#282A36'
TITLE = 'Image Cropper'
WIDTH, HEIGHT = 1280, 720
root = tk.Tk()
root.title(TITLE)
root.configure(background=BACKGROUND)
# Get the screen width and height
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Calculate the position to center the window
x = (screen_width - WIDTH) // 2
y = (screen_height - HEIGHT) // 2
# Set the window geometry
root.geometry('%dx%d+%d+%d' % (WIDTH, HEIGHT, x, y))
# # Make the window fullscreen
# root.state('zoomed')
# # Make the window borderless
# root.overrideredirect(True)
app = Application(root, background=BACKGROUND)
app.pack(side=tk.TOP, fill=tk.BOTH, expand=tk.TRUE)
app.mainloop()
我想要做的是:
我试图定义一个全局变量.
我发现应用程序窗口的宽度和高度是在代码末尾定义的(第185行) 源图像在‘类应用程序(tk.Frame)’中定义(第135行)
我不确定我是误解了全局变量,还是别的什么.但是我不知道如何用图像中的值填充WIDTH, HEIGHT
(第185行).
我试着添加
global image_size
image_size = img.width(),img.height()
到‘类应用程序(tk.Frame)’
然后用它,就像这样
WIDTH, HEIGHT = image_size
但这不管用,有谁介意帮我一下吗?