整理文件
This commit is contained in:
parent
f682fafc93
commit
a0af1a9fbf
83
README.md
83
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`
|
||||
|
||||
## 隐私说明
|
||||
|
||||
本程序仅在本地运行,不会将任何数据发送到互联网。所有剪贴板内容仅保存在本地文件中。
|
@ -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 - 检测到剪贴板文本变化
|
||||
|
@ -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)
|
@ -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`
|
||||
|
||||
## 隐私说明
|
||||
|
||||
本程序仅在本地运行,不会将任何数据发送到互联网。所有剪贴板内容仅保存在本地文件中。
|
Loading…
Reference in New Issue
Block a user