From a0af1a9fbfe98d074b758e9df215b0818dbec70e Mon Sep 17 00:00:00 2001 From: cyonjan Date: Wed, 30 Jul 2025 22:14:37 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B4=E7=90=86=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 83 ++++++++++ clipboard_monitor.log | 2 + clipboard_monitor.py | 304 ------------------------------------ clipboard_monitor_readme.md | 83 ---------- 4 files changed, 85 insertions(+), 387 deletions(-) delete mode 100644 clipboard_monitor.py delete mode 100644 clipboard_monitor_readme.md diff --git a/README.md b/README.md index e69de29..039787b 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,83 @@ +# 剪贴板监控程序 + +## 简介 + +这是一个基于Windows 64位系统的剪贴板实时监控程序,使用Python 3.11及以上版本开发。程序在后台运行,当检测到剪贴板内容变化时,会记录剪贴板内容并显示通知提示。支持文本和图片媒体的记录。 + +## 功能特点 + +- 实时监控剪贴板变化 +- 自动记录剪贴板历史内容 +- 支持图片媒体的记录和保存 +- 系统托盘图标,最小化运行 +- 可暂停/继续监控 +- 查看历史记录 +- 支持开机自启动 + +## 系统要求 + +- Windows 64位操作系统 +- Python 3.11或更高版本 +- 必要的Python库:pyperclip, pystray, pillow (PIL), pywin32 + +## 安装步骤 + +1. 确保已安装Python 3.11或更高版本 +2. 双击运行`start_clipboard_monitor.bat`,脚本会自动检查并安装必要的库 + +## 使用方法 + +### 启动程序 + +双击运行`start_clipboard_monitor.bat`文件即可启动剪贴板监控程序。程序启动后会在系统托盘显示图标。 + +### 设置开机自启动 + +如果希望程序在Windows启动时自动运行,请双击运行`setup_autostart.bat`文件,它会在Windows的启动文件夹中创建必要的快捷方式。 + +### 使用界面 + +程序启动后会在系统托盘区域显示一个图标,右键点击图标可以看到以下选项: + +- **显示主窗口**:打开主界面,查看剪贴板历史记录 +- **暂停/继续监控**:临时暂停或继续监控剪贴板 +- **清空历史记录**:删除所有已记录的剪贴板历史 +- **退出**:完全退出程序 + +### 主窗口 + +在主窗口中,您可以: + +- 查看所有剪贴板历史记录 +- 使用按钮暂停/继续监控 +- 清空历史记录 +- 退出程序 + +## 文件说明 + +- `clipboard_monitor.py`:主程序文件 +- `start_clipboard_monitor.bat`:启动脚本 +- `setup_autostart.bat`:设置开机自启动脚本 +- `clipboard_monitor.log`:程序运行日志 +- `clipboard_history.txt`:剪贴板历史记录 +- `clipboard_media/`:保存剪贴板图片的文件夹 + +## 注意事项 + +1. 程序会在后台持续运行,如需完全退出,请通过系统托盘图标的"退出"选项或主窗口的"退出程序"按钮退出 +2. 剪贴板历史记录保存在程序所在目录的`clipboard_history.txt`文件中 +3. 剪贴板中的图片会保存在`clipboard_media`文件夹中,文本记录中会包含图片文件的引用 +4. 如果遇到问题,可以查看`clipboard_monitor.log`日志文件了解详情 + +## 故障排除 + +如果程序无法正常启动或运行,请检查: + +1. 确认Python版本是否为3.11或更高 +2. 确认已安装所需的库:pyperclip, pystray, pillow, pywin32 +3. 查看`clipboard_monitor.log`日志文件,了解错误详情 +4. 如果提示缺少库,可以手动安装:`pip install pyperclip pystray pillow pywin32` + +## 隐私说明 + +本程序仅在本地运行,不会将任何数据发送到互联网。所有剪贴板内容仅保存在本地文件中。 \ No newline at end of file diff --git a/clipboard_monitor.log b/clipboard_monitor.log index 7d89b87..0c4ec43 100644 --- a/clipboard_monitor.log +++ b/clipboard_monitor.log @@ -33,3 +33,5 @@ SystemExit: 0 2025-07-30 16:15:36,353 - INFO - 检测到剪贴板图片变化 2025-07-30 16:15:36,385 - INFO - 图片已保存到: clipboard_media\20250730_161536_7842fbf8.png 2025-07-30 16:15:57,592 - INFO - 检测到剪贴板文本变化 +2025-07-30 21:57:53,972 - INFO - 剪贴板监控程序已启动 +2025-07-30 21:58:05,028 - INFO - 检测到剪贴板文本变化 diff --git a/clipboard_monitor.py b/clipboard_monitor.py deleted file mode 100644 index 5ab7585..0000000 --- a/clipboard_monitor.py +++ /dev/null @@ -1,304 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -剪贴板监控程序 - -该程序在后台运行,实时监控Windows系统剪贴板的变化, -当检测到剪贴板内容变化时,记录内容并输出提示。 -支持文本和图片媒体的记录。 -""" - -import time -import threading -import sys -import os -import datetime -import uuid -import io -import pyperclip -from pystray import Icon, Menu, MenuItem -from PIL import Image, ImageDraw, ImageGrab -import tkinter as tk -from tkinter import messagebox -import logging -import win32clipboard -from io import BytesIO - -# 配置日志 -logging.basicConfig( - level=logging.INFO, - format='%(asctime)s - %(levelname)s - %(message)s', - handlers=[ - logging.FileHandler("clipboard_monitor.log", encoding='utf-8'), - logging.StreamHandler() - ] -) - -class ClipboardMonitor: - def __init__(self): - self.previous_clipboard = "" - self.previous_image_hash = None - self.monitoring = True - self.paused = False - self.log_file = "clipboard_history.txt" - self.media_folder = "clipboard_media" - - # 确保媒体文件夹存在 - if not os.path.exists(self.media_folder): - os.makedirs(self.media_folder) - - self.setup_gui() - self.create_tray_icon() - - def setup_gui(self): - """设置GUI窗口,但默认不显示""" - self.root = tk.Tk() - self.root.title("剪贴板监控") - self.root.geometry("400x300") - self.root.protocol("WM_DELETE_WINDOW", self.hide_window) - - # 创建文本区域显示剪贴板历史 - self.text_area = tk.Text(self.root, wrap=tk.WORD) - self.text_area.pack(expand=True, fill=tk.BOTH, padx=10, pady=10) - - # 创建按钮框架 - button_frame = tk.Frame(self.root) - button_frame.pack(fill=tk.X, padx=10, pady=5) - - # 添加按钮 - tk.Button(button_frame, text="暂停监控", command=self.toggle_pause).pack(side=tk.LEFT, padx=5) - tk.Button(button_frame, text="清空历史", command=self.clear_history).pack(side=tk.LEFT, padx=5) - tk.Button(button_frame, text="退出程序", command=self.exit_app).pack(side=tk.RIGHT, padx=5) - - # 默认隐藏窗口 - self.root.withdraw() - - def create_tray_icon(self): - """创建系统托盘图标""" - # 创建图标 - image = self.create_icon_image() - - # 创建菜单 - menu = Menu( - MenuItem('显示主窗口', self.show_window), - MenuItem('暂停/继续监控', self.toggle_pause), - MenuItem('清空历史记录', self.clear_history), - MenuItem('退出', self.exit_app) - ) - - # 创建托盘图标 - self.icon = Icon("clipboard_monitor", image, "剪贴板监控", menu) - - # 在单独的线程中运行图标 - threading.Thread(target=self.icon.run, daemon=True).start() - - def create_icon_image(self): - """创建托盘图标图像""" - # 创建一个32x32的图像,白色背景 - image = Image.new('RGB', (32, 32), color=(255, 255, 255)) - d = ImageDraw.Draw(image) - - # 绘制剪贴板图标 - d.rectangle([(8, 8), (24, 24)], outline=(0, 0, 0), width=2) - d.rectangle([(12, 4), (20, 8)], fill=(0, 0, 0)) - - return image - - def show_window(self): - """显示主窗口""" - self.root.deiconify() - self.root.lift() - self.update_text_area() - - def hide_window(self): - """隐藏主窗口""" - self.root.withdraw() - - def toggle_pause(self): - """切换暂停/继续监控状态""" - self.paused = not self.paused - status = "暂停" if self.paused else "继续" - logging.info(f"监控已{status}") - self.show_notification(f"剪贴板监控已{status}") - - def clear_history(self): - """清空历史记录""" - try: - with open(self.log_file, 'w', encoding='utf-8') as f: - f.write("") - self.update_text_area() - logging.info("历史记录已清空") - self.show_notification("历史记录已清空") - except Exception as e: - logging.error(f"清空历史记录失败: {e}") - - def exit_app(self): - """退出应用程序""" - self.monitoring = False - if hasattr(self, 'icon'): - self.icon.stop() - self.root.quit() - # 不使用sys.exit(),避免引发SystemExit异常 - # 让程序自然退出 - - def show_notification(self, message): - """显示通知""" - if hasattr(self, 'icon'): - self.icon.notify(message) - - def update_text_area(self): - """更新文本区域内容""" - self.text_area.delete(1.0, tk.END) - try: - if os.path.exists(self.log_file): - with open(self.log_file, 'r', encoding='utf-8') as f: - content = f.read() - self.text_area.insert(tk.END, content) - except Exception as e: - logging.error(f"读取历史记录失败: {e}") - - def save_clipboard_content(self, content, media_path=None): - """保存剪贴板内容到文件""" - try: - timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - with open(self.log_file, 'a', encoding='utf-8') as f: - f.write(f"\n[{timestamp}]\n") - - # 如果有媒体文件,添加引用 - if media_path: - f.write(f"[图片文件: {media_path}]\n") - else: - f.write(f"{content}\n") - - f.write(f"{'='*50}\n") - - # 如果窗口可见,更新文本区域 - if self.root.winfo_viewable(): - self.update_text_area() - except Exception as e: - logging.error(f"保存剪贴板内容失败: {e}") - - def get_clipboard_image(self): - """尝试从剪贴板获取图片""" - try: - # 尝试使用PIL的ImageGrab获取剪贴板图片 - image = ImageGrab.grabclipboard() - if isinstance(image, Image.Image): - return image - return None - except Exception as e: - logging.error(f"获取剪贴板图片失败: {e}") - return None - - def save_image_to_file(self, image): - """保存图片到文件""" - try: - # 生成唯一文件名 - timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") - filename = f"{timestamp}_{uuid.uuid4().hex[:8]}.png" - filepath = os.path.join(self.media_folder, filename) - - # 保存图片 - image.save(filepath) - logging.info(f"图片已保存到: {filepath}") - return filepath - except Exception as e: - logging.error(f"保存图片失败: {e}") - return None - - def get_image_hash(self, image): - """获取图片的简单哈希值用于比较""" - if not image: - return None - try: - # 缩小图片以加快哈希计算 - small_image = image.resize((32, 32), Image.LANCZOS) - # 转换为灰度 - gray_image = small_image.convert("L") - # 获取像素数据 - pixels = list(gray_image.getdata()) - # 简单哈希:将像素值二值化并转为字符串 - binary_pixels = ['1' if p > 128 else '0' for p in pixels] - return ''.join(binary_pixels) - except Exception as e: - logging.error(f"计算图片哈希失败: {e}") - return None - - def monitor_clipboard(self): - """监控剪贴板变化""" - try: - # 获取初始剪贴板内容 - self.previous_clipboard = pyperclip.paste() - # 获取初始图片(如果有) - initial_image = self.get_clipboard_image() - if initial_image: - self.previous_image_hash = self.get_image_hash(initial_image) - except Exception as e: - self.previous_clipboard = "" - self.previous_image_hash = None - logging.error(f"获取初始剪贴板内容失败: {e}") - - while self.monitoring: - try: - if not self.paused: - # 检查是否有图片 - current_image = self.get_clipboard_image() - if current_image: - current_image_hash = self.get_image_hash(current_image) - - # 如果图片变化了 - if current_image_hash != self.previous_image_hash: - logging.info("检测到剪贴板图片变化") - self.show_notification("检测到新的剪贴板图片") - - # 保存图片到文件 - image_path = self.save_image_to_file(current_image) - if image_path: - # 保存引用到日志 - self.save_clipboard_content("", image_path) - - # 更新上一次的图片哈希 - self.previous_image_hash = current_image_hash - else: - # 获取当前文本内容 - current_clipboard = pyperclip.paste() - - # 如果文本内容变化了 - if current_clipboard != self.previous_clipboard: - logging.info("检测到剪贴板文本变化") - self.show_notification("检测到新的剪贴板内容") - - # 保存新内容 - self.save_clipboard_content(current_clipboard) - - # 更新上一次的内容 - self.previous_clipboard = current_clipboard - except Exception as e: - logging.error(f"监控剪贴板时出错: {e}") - - # 休眠一段时间再检查 - time.sleep(0.5) - - def run(self): - """运行监控程序""" - # 启动监控线程 - monitor_thread = threading.Thread(target=self.monitor_clipboard, daemon=True) - monitor_thread.start() - - # 显示启动通知 - self.show_notification("剪贴板监控已启动") - logging.info("剪贴板监控程序已启动") - - # 运行主循环 - self.root.mainloop() - - -if __name__ == "__main__": - try: - monitor = ClipboardMonitor() - monitor.run() - except Exception as e: - logging.critical(f"程序启动失败: {e}") - messagebox.showerror("错误", f"程序启动失败: {e}") - sys.exit(1) \ No newline at end of file diff --git a/clipboard_monitor_readme.md b/clipboard_monitor_readme.md deleted file mode 100644 index 039787b..0000000 --- a/clipboard_monitor_readme.md +++ /dev/null @@ -1,83 +0,0 @@ -# 剪贴板监控程序 - -## 简介 - -这是一个基于Windows 64位系统的剪贴板实时监控程序,使用Python 3.11及以上版本开发。程序在后台运行,当检测到剪贴板内容变化时,会记录剪贴板内容并显示通知提示。支持文本和图片媒体的记录。 - -## 功能特点 - -- 实时监控剪贴板变化 -- 自动记录剪贴板历史内容 -- 支持图片媒体的记录和保存 -- 系统托盘图标,最小化运行 -- 可暂停/继续监控 -- 查看历史记录 -- 支持开机自启动 - -## 系统要求 - -- Windows 64位操作系统 -- Python 3.11或更高版本 -- 必要的Python库:pyperclip, pystray, pillow (PIL), pywin32 - -## 安装步骤 - -1. 确保已安装Python 3.11或更高版本 -2. 双击运行`start_clipboard_monitor.bat`,脚本会自动检查并安装必要的库 - -## 使用方法 - -### 启动程序 - -双击运行`start_clipboard_monitor.bat`文件即可启动剪贴板监控程序。程序启动后会在系统托盘显示图标。 - -### 设置开机自启动 - -如果希望程序在Windows启动时自动运行,请双击运行`setup_autostart.bat`文件,它会在Windows的启动文件夹中创建必要的快捷方式。 - -### 使用界面 - -程序启动后会在系统托盘区域显示一个图标,右键点击图标可以看到以下选项: - -- **显示主窗口**:打开主界面,查看剪贴板历史记录 -- **暂停/继续监控**:临时暂停或继续监控剪贴板 -- **清空历史记录**:删除所有已记录的剪贴板历史 -- **退出**:完全退出程序 - -### 主窗口 - -在主窗口中,您可以: - -- 查看所有剪贴板历史记录 -- 使用按钮暂停/继续监控 -- 清空历史记录 -- 退出程序 - -## 文件说明 - -- `clipboard_monitor.py`:主程序文件 -- `start_clipboard_monitor.bat`:启动脚本 -- `setup_autostart.bat`:设置开机自启动脚本 -- `clipboard_monitor.log`:程序运行日志 -- `clipboard_history.txt`:剪贴板历史记录 -- `clipboard_media/`:保存剪贴板图片的文件夹 - -## 注意事项 - -1. 程序会在后台持续运行,如需完全退出,请通过系统托盘图标的"退出"选项或主窗口的"退出程序"按钮退出 -2. 剪贴板历史记录保存在程序所在目录的`clipboard_history.txt`文件中 -3. 剪贴板中的图片会保存在`clipboard_media`文件夹中,文本记录中会包含图片文件的引用 -4. 如果遇到问题,可以查看`clipboard_monitor.log`日志文件了解详情 - -## 故障排除 - -如果程序无法正常启动或运行,请检查: - -1. 确认Python版本是否为3.11或更高 -2. 确认已安装所需的库:pyperclip, pystray, pillow, pywin32 -3. 查看`clipboard_monitor.log`日志文件,了解错误详情 -4. 如果提示缺少库,可以手动安装:`pip install pyperclip pystray pillow pywin32` - -## 隐私说明 - -本程序仅在本地运行,不会将任何数据发送到互联网。所有剪贴板内容仅保存在本地文件中。 \ No newline at end of file