[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageTk
import os
class ImageCoordinateTool:
def __init__(self, root):
self.root = root
self.root.title("图片坐标点获取工具")
self.root.geometry("800x600")
# 设置中文字体支持
self.root.option_add("*Font", "SimHei 10")
self.image_path = None
self.original_img = None
self.photo_img = None
self.scale_factor = 1.0
# 创建界面
self.create_widgets()
def create_widgets(self):
# 顶部工具栏
top_frame = tk.Frame(self.root)
top_frame.pack(fill=tk.X, padx=10, pady=10)
# 打开图片按钮
open_btn = tk.Button(top_frame, text="打开图片", command=self.open_image)
open_btn.pack(side=tk.LEFT, padx=5)
# 坐标显示框
self.coord_label = tk.Label(top_frame, text="坐标: 0,0")
self.coord_label.pack(side=tk.LEFT, padx=20)
# 自动复制选项
self.auto_copy_var = tk.BooleanVar(value=True)
auto_copy_check = tk.Checkbutton(top_frame, text="自动复制坐标", variable=self.auto_copy_var)
auto_copy_check.pack(side=tk.LEFT, padx=20)
# 缩放控制
zoom_frame = tk.Frame(top_frame)
zoom_frame.pack(side=tk.RIGHT, padx=5)
tk.Label(zoom_frame, text="缩放:").pack(side=tk.LEFT)
self.zoom_in_btn = tk.Button(zoom_frame, text="+", command=self.zoom_in, width=3)
self.zoom_in_btn.pack(side=tk.LEFT, padx=2)
self.zoom_out_btn = tk.Button(zoom_frame, text="-", command=self.zoom_out, width=3)
self.zoom_out_btn.pack(side=tk.LEFT, padx=2)
# 重置视图按钮
reset_btn = tk.Button(zoom_frame, text="重置", command=self.reset_view, width=5)
reset_btn.pack(side=tk.LEFT, padx=2)
# 图片显示区域 - 使用带滚动条的框架
self.canvas_frame = tk.Frame(self.root)
self.canvas_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# 创建垂直滚动条
self.vscrollbar = tk.Scrollbar(self.canvas_frame, orient=tk.VERTICAL)
self.vscrollbar.pack(side=tk.RIGHT, fill=tk.Y)
# 创建水平滚动条
self.hscrollbar = tk.Scrollbar(self.canvas_frame, orient=tk.HORIZONTAL)
self.hscrollbar.pack(side=tk.BOTTOM, fill=tk.X)
# 创建画布
self.canvas = tk.Canvas(self.canvas_frame, bg="white",
yscrollcommand=self.vscrollbar.set,
xscrollcommand=self.hscrollbar.set)
self.canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 配置滚动条
self.vscrollbar.config(command=self.canvas.yview)
self.hscrollbar.config(command=self.canvas.xview)
# 绑定鼠标事件
self.canvas.bind("<Motion>", self.on_mouse_move)
self.canvas.bind("<Button-1>", self.on_click)
# 绑定滚轮事件(跨平台)
self.canvas.bind("<MouseWheel>", self.on_mouse_wheel) # Windows
self.canvas.bind("<Button-4>", self.on_mouse_wheel) # Linux
self.canvas.bind("<Button-5>", self.on_mouse_wheel) # Linux
# 状态栏
self.status_bar = tk.Label(self.root, text="就绪", bd=1, relief=tk.SUNKEN, anchor=tk.W)
self.status_bar.pack(side=tk.BOTTOM, fill=tk.X)
# 坐标点列表
self.points_frame = tk.Frame(self.root)
self.points_frame.pack(fill=tk.X, padx=10, pady=5)
tk.Label(self.points_frame, text="已选坐标点:").pack(side=tk.LEFT)
self.points_listbox = tk.Listbox(self.points_frame, width=50, height=3)
self.points_listbox.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=5)
copy_btn = tk.Button(self.points_frame, text="复制坐标", command=self.copy_coordinates)
copy_btn.pack(side=tk.LEFT, padx=5)
clear_btn = tk.Button(self.points_frame, text="清除坐标", command=self.clear_coordinates)
clear_btn.pack(side=tk.LEFT, padx=5)
# 存储选择的坐标点
self.points = []
def open_image(self):
# 打开文件对话框选择图片
file_path = filedialog.askopenfilename(
title="选择图片",
filetypes=[("图片文件", "*.png;*.jpg;*.jpeg;*.bmp;*.gif")]
)
if file_path:
self.image_path = file_path
self.load_image()
self.status_bar.config(text=f"已加载图片: {os.path.basename(file_path)}")
self.points = []
self.points_listbox.delete(0, tk.END)
def load_image(self):
if not self.image_path:
return
# 打开并显示图片
try:
self.original_img = Image.open(self.image_path)
self.scale_factor = 1.0
self.display_image()
except Exception as e:
messagebox.showerror("错误", f"无法加载图片: {str(e)}")
def display_image(self):
if not self.original_img:
return
# 缩放图片
width, height = self.original_img.size
new_width = int(width * self.scale_factor)
new_height = int(height * self.scale_factor)
img = self.original_img.resize((new_width, new_height), Image.LANCZOS)
self.photo_img = ImageTk.PhotoImage(img)
# 清除画布并显示图片
self.canvas.delete("all")
self.image_item = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.photo_img)
# 绘制已选的坐标点
for x, y in self.points:
scaled_x = x * self.scale_factor
scaled_y = y * self.scale_factor
self.draw_point(scaled_x, scaled_y)
# 更新画布滚动区域
self.canvas.config(scrollregion=self.canvas.bbox(tk.ALL))
# 重置视图
self.canvas.xview_moveto(0)
self.canvas.yview_moveto(0)
def draw_point(self, x, y):
# 在画布上绘制一个标记点和坐标文本
radius = 5
self.canvas.create_oval(x - radius, y - radius, x + radius, y + radius, fill="red")
self.canvas.create_text(x + 15, y - 15, text=f"{int(x / self.scale_factor)},{int(y / self.scale_factor)}",
fill="red", font=("SimHei", 10))
def on_mouse_move(self, event):
# 鼠标移动时更新坐标显示
if self.photo_img:
# 获取鼠标在画布上的坐标
canvas_x = self.canvas.canvasx(event.x)
canvas_y = self.canvas.canvasy(event.y)
# 获取鼠标在原图中的坐标
x = int(canvas_x / self.scale_factor)
y = int(canvas_y / self.scale_factor)
self.coord_label.config(text=f"坐标: {x},{y}")
def on_click(self, event):
# 左键点击时记录坐标点
if self.photo_img:
# 获取鼠标在画布上的坐标
canvas_x = self.canvas.canvasx(event.x)
canvas_y = self.canvas.canvasy(event.y)
# 获取鼠标在原图中的坐标
x = int(canvas_x / self.scale_factor)
y = int(canvas_y / self.scale_factor)
# 检查坐标是否在图片范围内
width, height = self.original_img.size
if 0 <= x < width and 0 <= y < height:
# 记录坐标点
self.points.append((x, y))
# 在画布上绘制点
self.draw_point(canvas_x, canvas_y)
# 更新坐标点列表
self.points_listbox.insert(tk.END, f"{x},{y}")
self.points_listbox.see(tk.END)
# 自动复制坐标
if self.auto_copy_var.get():
self.copy_last_coordinate()
def on_mouse_wheel(self, event):
# 鼠标滚轮缩放
if not self.photo_img:
return
# 获取鼠标在画布上的位置
x = self.canvas.canvasx(event.x)
y = self.canvas.canvasy(event.y)
# 计算缩放因子(Windows和Linux的event.delta不同)
if event.num == 5 or event.delta < 0: # 向下滚动 = 缩小
self.scale_factor /= 1.2
else: # 向上滚动 = 放大
self.scale_factor *= 1.2
# 限制缩放范围
self.scale_factor = max(0.1, min(self.scale_factor, 10.0))
# 重新显示图片
self.display_image()
# 保持鼠标位置不变
self.canvas.xview_moveto(x / (self.original_img.width * self.scale_factor))
self.canvas.yview_moveto(y / (self.original_img.height * self.scale_factor))
def copy_last_coordinate(self):
# 复制最后一个坐标点到剪贴板
if self.points:
x, y = self.points[-1]
coord_text = f"{x},{y}"
self.root.clipboard_clear()
self.root.clipboard_append(coord_text)
self.status_bar.config(text=f"坐标 {coord_text} 已复制到剪贴板")
def zoom_in(self):
# 放大图片
if self.original_img:
self.scale_factor *= 1.2
self.display_image()
def zoom_out(self):
# 缩小图片
if self.original_img:
self.scale_factor /= 1.2
self.display_image()
def reset_view(self):
# 重置视图
if self.original_img:
self.scale_factor = 1.0
self.display_image()
def copy_coordinates(self):
# 复制所有坐标点到剪贴板
if self.points:
coords_text = "\n".join([f"{x},{y}" for x, y in self.points])
self.root.clipboard_clear()
self.root.clipboard_append(coords_text)
self.status_bar.config(text="坐标已复制到剪贴板")
else:
messagebox.showinfo("提示", "没有选择任何坐标点")
def clear_coordinates(self):
# 清除所有坐标点
self.points = []
self.points_listbox.delete(0, tk.END)
self.display_image()
self.status_bar.config(text="坐标点已清除")
if __name__ == "__main__":
root = tk.Tk()
app = ImageCoordinateTool(root)
root.mainloop()