使用Python結(jié)合Tkinter和PyAutoGUI開發(fā)精確截圖工具
運(yùn)行結(jié)果


全部代碼
import tkinter as tk
from tkinter import ttk
import pyautogui
import numpy as np
from PIL import Image, ImageTk, ImageGrab
import os
from datetime import datetime
import time
class ImprovedScreenshotTool:
def __init__(self):
# Create the main window
self.root = tk.Tk()
self.root.title("精確截圖工具")
self.root.geometry("400x200")
self.root.resizable(False, False)
# Center the window
self.center_window()
# Create a frame for the controls
control_frame = ttk.Frame(self.root)
control_frame.pack(pady=10, fill=tk.X)
# Create and place the screenshot button
self.screenshot_btn = ttk.Button(
control_frame,
text="開始截圖",
width=20,
command=self.prepare_screenshot
)
self.screenshot_btn.pack(pady=10)
# Status label
self.status_label = ttk.Label(control_frame, text="就緒")
self.status_label.pack(pady=5)
# Preview frame
self.preview_frame = ttk.LabelFrame(self.root, text="最近截圖預(yù)覽")
self.preview_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
self.preview_label = ttk.Label(self.preview_frame)
self.preview_label.pack(fill=tk.BOTH, expand=True)
# Variables for region selection
self.start_x = 0
self.start_y = 0
self.end_x = 0
self.end_y = 0
# Save directory
pictures_dir = os.path.join(os.path.expanduser("~"), "Pictures")
if os.path.exists(pictures_dir):
self.save_dir = pictures_dir
else:
self.save_dir = os.path.join(os.path.expanduser("~"), "Desktop")
# Make sure the directory exists
if not os.path.exists(self.save_dir):
os.makedirs(self.save_dir)
# Last saved file
self.last_saved_file = None
def center_window(self):
# Get screen width and height
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
# Calculate position
x = (screen_width - 400) // 2
y = (screen_height - 200) // 2
# Set window position
self.root.geometry(f"400x200+{x}+{y}")
def prepare_screenshot(self):
# Update status
self.status_label.config(text="準(zhǔn)備截圖...")
self.root.update() # Force UI update
# Minimize window
self.root.withdraw()
# Wait a moment for UI to update
self.root.after(500, self.take_screenshot)
def take_screenshot(self):
# Create overlay window for selection
overlay = ScreenshotOverlay(self)
self.root.wait_window(overlay.overlay)
# If cancelled, just return to normal
if not hasattr(self, 'screenshot_region') or not self.screenshot_region:
self.root.deiconify()
self.status_label.config(text="已取消截圖")
return
# Get the selection coordinates
x1, y1, x2, y2 = self.screenshot_region
# Convert to proper coordinates (top-left, bottom-right)
left = min(x1, x2)
top = min(y1, y2)
right = max(x1, x2)
bottom = max(y1, y2)
# Ensure minimum size
if right - left < 5 or bottom - top < 5:
self.root.deiconify()
self.status_label.config(text="選擇區(qū)域太小")
return
# Take screenshot
try:
# Wait a moment to ensure overlay is gone
time.sleep(0.3)
# Capture the screen region
screenshot = pyautogui.screenshot(region=(left, top, right-left, bottom-top))
# Generate filename
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = os.path.join(self.save_dir, f"screenshot_{timestamp}.png")
# Save the screenshot
screenshot.save(filename)
self.last_saved_file = filename
# Update preview
self.update_preview(screenshot)
# Update status
self.status_label.config(text=f"截圖已保存: {os.path.basename(filename)}")
except Exception as e:
self.status_label.config(text=f"截圖錯(cuò)誤: {str(e)}")
# Show the main window again
self.root.deiconify()
def update_preview(self, image):
# Resize for preview if needed
preview_width = 360
preview_height = 100
width, height = image.size
ratio = min(preview_width/width, preview_height/height)
new_size = (int(width * ratio), int(height * ratio))
resized = image.resize(new_size, Image.LANCZOS)
# Convert to PhotoImage
photo = ImageTk.PhotoImage(resized)
# Update label
self.preview_label.config(image=photo)
self.preview_label.image = photo # Keep a reference
def run(self):
self.root.mainloop()
class ScreenshotOverlay:
def __init__(self, parent):
self.parent = parent
# Create fullscreen overlay window
self.overlay = tk.Toplevel()
self.overlay.attributes('-fullscreen', True)
self.overlay.attributes('-alpha', 0.3)
self.overlay.attributes('-topmost', True)
# Make it semi-transparent with dark background
self.overlay.configure(bg='black')
# Add a canvas for drawing
self.canvas = tk.Canvas(
self.overlay,
bg='#1a1a1a',
highlightthickness=0,
cursor="crosshair"
)
self.canvas.pack(fill=tk.BOTH, expand=True)
# Variables for tracking
self.start_x = None
self.start_y = None
self.rect_id = None
self.magnifier_id = None
self.coords_text_id = None
# Instructions text
self.canvas.create_text(
self.overlay.winfo_screenwidth() // 2,
50,
text="單擊并拖動鼠標(biāo)選擇截圖區(qū)域 | 按ESC取消",
fill="white",
font=("Arial", 16)
)
# Bind events
self.canvas.bind("<ButtonPress-1>", self.on_press)
self.canvas.bind("<B1-Motion>", self.on_drag)
self.canvas.bind("<ButtonRelease-1>", self.on_release)
self.overlay.bind("<Escape>", self.on_cancel)
# Take a full screenshot for the magnifier
self.screen_image = pyautogui.screenshot()
self.screen_array = np.array(self.screen_image)
def on_press(self, event):
# Record start position
self.start_x = event.x
self.start_y = event.y
# Create rectangle
self.rect_id = self.canvas.create_rectangle(
self.start_x, self.start_y,
self.start_x, self.start_y,
outline="#00ff00", width=2, fill=""
)
# Create magnifier circle
self.magnifier_id = self.canvas.create_oval(
event.x - 50, event.y - 50,
event.x + 50, event.y + 50,
outline="#ffffff", width=2, fill="#333333"
)
# Create coordinate display
self.coords_text_id = self.canvas.create_text(
event.x, event.y - 60,
text=f"({event.x}, {event.y})",
fill="#ffffff",
font=("Arial", 10)
)
def on_drag(self, event):
# Update rectangle
self.canvas.coords(
self.rect_id,
self.start_x, self.start_y,
event.x, event.y
)
# Update magnifier position
self.canvas.coords(
self.magnifier_id,
event.x - 50, event.y - 50,
event.x + 50, event.y + 50
)
# Update coordinate display
self.canvas.coords(
self.coords_text_id,
event.x, event.y - 60
)
self.canvas.itemconfig(
self.coords_text_id,
text=f"({event.x}, {event.y}) | 大小: {abs(event.x - self.start_x)}x{abs(event.y - self.start_y)}"
)
# Draw selection area with fill (using a valid color format)
self.canvas.itemconfig(
self.rect_id,
fill="#22ff22" # Changed to a valid semi-transparent green
)
def on_release(self, event):
# Store the selection coordinates in the parent
self.parent.screenshot_region = (
self.start_x, self.start_y,
event.x, event.y
)
# Close the overlay
self.overlay.destroy()
def on_cancel(self, event):
# Reset parent's screenshot region
self.parent.screenshot_region = None
# Close overlay
self.overlay.destroy()
if __name__ == "__main__":
app = ImprovedScreenshotTool()
app.run()
1. 工具介紹
該工具具有以下功能:
- 自定義截圖區(qū)域:通過鼠標(biāo)拖動選擇截圖區(qū)域。
- 自動保存截圖:截圖會自動保存到
Pictures文件夾或桌面。 - 截圖預(yù)覽:最近一次截圖會在工具界面中進(jìn)行預(yù)覽。
- 用戶友好的操作提示:提供狀態(tài)提示,讓用戶清楚當(dāng)前操作。
2. 主要技術(shù)棧
本工具基于以下 Python 庫實(shí)現(xiàn):
tkinter:用于構(gòu)建 GUI 界面。pyautogui:用于屏幕截圖。PIL (Pillow):用于圖像處理和預(yù)覽。numpy:用于優(yōu)化圖像處理。datetime和os:用于管理文件存儲。
3. 代碼結(jié)構(gòu)解析
3.1 主窗口的創(chuàng)建
import tkinter as tk
from tkinter import ttk
import pyautogui
import numpy as np
from PIL import Image, ImageTk
import os
from datetime import datetime
import time
class ImprovedScreenshotTool:
def __init__(self):
self.root = tk.Tk()
self.root.title("精確截圖工具")
self.root.geometry("400x200")
self.root.resizable(False, False)
self.center_window()
self.create_widgets()
self.setup_save_directory()
def center_window(self):
screen_width = self.root.winfo_screenwidth()
screen_height = self.root.winfo_screenheight()
x = (screen_width - 400) // 2
y = (screen_height - 200) // 2
self.root.geometry(f"400x200+{x}+{y}")
功能解析:
- 創(chuàng)建
Tk窗口,設(shè)置標(biāo)題、大小并居中。 center_window方法用于獲取屏幕尺寸并計(jì)算窗口居中位置。
3.2 創(chuàng)建 GUI 組件
def create_widgets(self):
control_frame = ttk.Frame(self.root)
control_frame.pack(pady=10, fill=tk.X)
self.screenshot_btn = ttk.Button(control_frame, text="開始截圖", width=20, command=self.prepare_screenshot)
self.screenshot_btn.pack(pady=10)
self.status_label = ttk.Label(control_frame, text="就緒")
self.status_label.pack(pady=5)
self.preview_frame = ttk.LabelFrame(self.root, text="最近截圖預(yù)覽")
self.preview_frame.pack(pady=10, padx=10, fill=tk.BOTH, expand=True)
self.preview_label = ttk.Label(self.preview_frame)
self.preview_label.pack(fill=tk.BOTH, expand=True)
功能解析:
- 創(chuàng)建按鈕
開始截圖,綁定prepare_screenshot方法。 - 狀態(tài)標(biāo)簽用于提示當(dāng)前狀態(tài)。
preview_frame用于顯示最近截圖的預(yù)覽。
3.3 截圖邏輯
def prepare_screenshot(self):
self.status_label.config(text="準(zhǔn)備截圖...")
self.root.update()
self.root.withdraw()
self.root.after(500, self.take_screenshot)
功能解析:
- 按下截圖按鈕后,狀態(tài)標(biāo)簽顯示 “準(zhǔn)備截圖…”。
withdraw()讓主窗口最小化,避免干擾截圖。after(500, self.take_screenshot)讓窗口延遲 0.5 秒后調(diào)用take_screenshot。
def take_screenshot(self):
overlay = ScreenshotOverlay(self)
self.root.wait_window(overlay.overlay)
if not hasattr(self, 'screenshot_region') or not self.screenshot_region:
self.root.deiconify()
self.status_label.config(text="已取消截圖")
return
x1, y1, x2, y2 = self.screenshot_region
left, top = min(x1, x2), min(y1, y2)
right, bottom = max(x1, x2), max(y1, y2)
if right - left < 5 or bottom - top < 5:
self.root.deiconify()
self.status_label.config(text="選擇區(qū)域太小")
return
time.sleep(0.3)
screenshot = pyautogui.screenshot(region=(left, top, right-left, bottom-top))
filename = os.path.join(self.save_dir, f"screenshot_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png")
screenshot.save(filename)
self.last_saved_file = filename
self.update_preview(screenshot)
self.status_label.config(text=f"截圖已保存: {os.path.basename(filename)}")
self.root.deiconify()
功能解析:
ScreenshotOverlay負(fù)責(zé)創(chuàng)建全屏幕覆蓋窗口,允許用戶選擇截圖區(qū)域。- 獲取選定區(qū)域的坐標(biāo),并檢查區(qū)域大小是否有效。
pyautogui.screenshot(region=(left, top, width, height))實(shí)現(xiàn)精準(zhǔn)截圖。- 保存截圖并更新預(yù)覽區(qū)域。
3.4 截圖選擇區(qū)域的實(shí)現(xiàn)
class ScreenshotOverlay:
def __init__(self, parent):
self.parent = parent
self.overlay = tk.Toplevel()
self.overlay.attributes('-fullscreen', True)
self.overlay.attributes('-alpha', 0.3)
self.overlay.attributes('-topmost', True)
self.overlay.configure(bg='black')
self.canvas = tk.Canvas(self.overlay, bg='#1a1a1a', highlightthickness=0, cursor="crosshair")
self.canvas.pack(fill=tk.BOTH, expand=True)
self.canvas.bind("<ButtonPress-1>", self.on_press)
self.canvas.bind("<B1-Motion>", self.on_drag)
self.canvas.bind("<ButtonRelease-1>", self.on_release)
self.overlay.bind("<Escape>", self.on_cancel)
功能解析:
- 創(chuàng)建全屏幕透明窗口,允許用戶使用鼠標(biāo)選擇截圖區(qū)域。
- 監(jiān)聽鼠標(biāo)點(diǎn)擊 (
on_press)、拖動 (on_drag)、釋放 (on_release) 事件。
以上就是使用Python結(jié)合Tkinter和PyAutoGUI開發(fā)精確截圖工具的詳細(xì)內(nèi)容,更多關(guān)于Python Tkinter PyAutoGUI截圖工具的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Python Selenium XPath根據(jù)文本內(nèi)容查找元素的方法
這篇文章主要介紹了Python Selenium XPath根據(jù)文本內(nèi)容查找元素的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12
詳解tensorflow之過擬合問題實(shí)戰(zhàn)
這篇文章主要介紹了詳解tensorflow之過擬合問題實(shí)戰(zhàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Python如何計(jì)算兩個(gè)不同類型列表的相似度
在編程中,經(jīng)常需要比較兩個(gè)列表的相似度,尤其是當(dāng)這兩個(gè)列表包含不同類型的元素時(shí),下面小編就來講講如何使用Python計(jì)算兩個(gè)不同類型列表的相似度吧2025-02-02
python將秒數(shù)轉(zhuǎn)化為時(shí)間格式的實(shí)例
今天小編就為大家分享一篇python將秒數(shù)轉(zhuǎn)化為時(shí)間格式的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09
Python利用腳本實(shí)現(xiàn)自動發(fā)送電子郵件
這篇文章主要為大家詳細(xì)介紹了Python如何利用腳本實(shí)現(xiàn)自動發(fā)送電子郵件功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01

