使用Python結(jié)合Tkinter和PyAutoGUI開發(fā)精確截圖工具
更新時間:2025年03月31日 08:27:13 作者:winfredzhang
在日常工作中,截圖是一個非常常見的需求,雖然?Windows?自帶截圖工具,但有時我們需要更精確的截圖方式,比如選取特定區(qū)域、快速保存截圖并進(jìn)行預(yù)覽,本篇博客將介紹一個使用?Python?結(jié)合?Tkinter?和?PyAutoGUI?開發(fā)的精確截圖工具,需要的朋友可以參考下
運行結(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"截圖錯誤: {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 庫實現(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
方法用于獲取屏幕尺寸并計算窗口居中位置。
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))
實現(xiàn)精準(zhǔn)截圖。- 保存截圖并更新預(yù)覽區(qū)域。
3.4 截圖選擇區(qū)域的實現(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)點擊 (
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í)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-12-12python將秒數(shù)轉(zhuǎn)化為時間格式的實例
今天小編就為大家分享一篇python將秒數(shù)轉(zhuǎn)化為時間格式的實例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-09-09Python利用腳本實現(xiàn)自動發(fā)送電子郵件
這篇文章主要為大家詳細(xì)介紹了Python如何利用腳本實現(xiàn)自動發(fā)送電子郵件功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-01-01