Python+Tkinter+PyAutoGUI开发精确截图工具实例详解

winfredzhang 2025-03-31 11:56:55编程技术
1006

在现代软件开发中,自动化和图形用户界面(GUI)的结合为提高效率和用户体验提供了强大的工具。Python,作为一种广受欢迎的编程语言,以其简洁的语法和强大的库支持,成为开发自动化脚本和GUI应用的首选。Tkinter作为Python的标准GUI库,以其简单易用而著称,而PyAutoGUI则允许我们控制鼠标和键盘,实现屏幕自动化操作。本文将详细介绍如何结合使用Python、Tkinter和PyAutoGUI来开发一个精确截图工具。这个工具不仅能够提供基本的截图功能,还能通过自动化技术精确选择截图区域,为用户提供极大的便利和灵活性。

运行结果

Python+Tkinter+PyAutoGUI开发精确截图工具实例详解

Python+Tkinter+PyAutoGUI开发精确截图工具实例详解

全部代码

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="最近截图预览")
        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="准备截图...")
        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="选择区域太小")
            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="单击并拖动鼠标选择截图区域 | 按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. 工具介绍

该工具具有以下功能:

  • 自定义截图区域:通过鼠标拖动选择截图区域。

  • 自动保存截图:截图会自动保存到 Pictures 文件夹或桌面。

  • 截图预览:最近一次截图会在工具界面中进行预览。

  • 用户友好的操作提示:提供状态提示,让用户清楚当前操作。

2. 主要技术栈

本工具基于以下 Python 库实现:

  • tkinter:用于构建 GUI 界面。

  • pyautogui:用于屏幕截图。

  • PIL (Pillow):用于图像处理和预览。

  • numpy:用于优化图像处理。

  • datetime 和 os:用于管理文件存储。

3. 代码结构解析

3.1 主窗口的创建

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}")

功能解析:

  • 创建 Tk 窗口,设置标题、大小并居中。

  • center_window 方法用于获取屏幕尺寸并计算窗口居中位置。

3.2 创建 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="最近截图预览")
        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)

功能解析:

  • 创建按钮 开始截图,绑定 prepare_screenshot 方法。

  • 状态标签用于提示当前状态。

  • preview_frame 用于显示最近截图的预览。

3.3 截图逻辑

    def prepare_screenshot(self):
        self.status_label.config(text="准备截图...")
        self.root.update()
        self.root.withdraw()
        self.root.after(500, self.take_screenshot)

功能解析:

  • 按下截图按钮后,状态标签显示 “准备截图…”。

  • withdraw() 让主窗口最小化,避免干扰截图。

  • after(500, self.take_screenshot) 让窗口延迟 0.5 秒后调用 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="选择区域太小")
            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 负责创建全屏幕覆盖窗口,允许用户选择截图区域。

  • 获取选定区域的坐标,并检查区域大小是否有效。

  • pyautogui.screenshot(region=(left, top, width, height)) 实现精准截图。

  • 保存截图并更新预览区域。

3.4 截图选择区域的实现

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)

功能解析:

  • 创建全屏幕透明窗口,允许用户使用鼠标选择截图区域。

  • 监听鼠标点击 (on_press)、拖动 (on_drag)、释放 (on_release) 事件。

总结

本文详细介绍了如何利用Python的强大功能,结合Tkinter和PyAutoGUI库,开发出一个精确截图工具。通过Tkinter构建用户友好的界面,让用户能够轻松选择截图区域;而PyAutoGUI则负责实现自动化的屏幕操作,包括精确定位和截图。这种结合不仅提高了开发效率,也极大地增强了程序的功能性和用户体验。通过本文的实例详解,读者可以了解到如何将这些技术应用到实际项目中,开发出既实用又高效的自动化工具。随着技术的不断进步,这种类型的工具将在日常工作和专业领域中发挥越来越重要的作用。

Python Tkinter PyAutoGUI 截图工具
THE END
蜜芽
故事不长,也不难讲,四字概括,毫无意义。

相关推荐

Python yield 用法大全:轻松掌握生成器与迭代器设计
在Python中,yield关键字是构建生成器的核心工具,它通过状态保存机制实现了高效的内存管理和惰性计算。与传统的迭代器实现相比,yield能将迭代器设计从复杂的类定义简化为直...
2025-09-15 编程技术
1216

基于Python的旅游数据分析可视化系统【2026最新】
本研究成功开发了基于Python+Django+Vue+MySQL的旅游数据分析可视化系统,实现了从数据采集到可视化展示的全流程管理。系统采用前后端分离架构,前端通过Vue框架构建响应式界...
2025-09-13 编程技术
1165

手把手教你用Python读取txt文件:从基础到实战的完整教程
Python作为数据处理的利器,文件读写是其基础核心功能。掌握txt文件读取不仅能处理日志、配置文件等常见场景,更是理解Python文件I/O的基石。本文ZHANID工具网将从基础语法到...
2025-09-12 编程技术
1077

Python Flask 入门指南:从零开始搭建你的第一个 Web 应用
Flask作为 Python 中最轻量级且灵活的 Web 框架之一,特别适合初学者快速上手 Web 应用开发。本文将带你一步步了解如何在本地环境中安装 Flask、创建一个简单的 Web 应用,并...
2025-09-11 编程技术
1021

Python 如何调用 MediaPipe?详细安装与使用指南
MediaPipe 是 Google 开发的跨平台机器学习框架,支持实时处理视觉、音频和文本数据。本文脚本之家将系统讲解 Python 环境下 MediaPipe 的安装、配置及核心功能调用方法,涵盖...
2025-09-10 编程技术
1093

基于Python开发一个利率计算器的思路及示例代码
利率计算是金融领域的基础需求,涵盖贷款利息、存款收益、投资回报等场景。传统计算依赖手工公式或Excel表格,存在效率低、易出错等问题。Python凭借其简洁的语法和强大的数学...
2025-09-09 编程技术
1109