目录
- 一、概述:为什么需要剪贴板历史管理
- 二、功能特性全解析
- 2.1 核心功能
- 2.2 增强功能
- 三、效果展示
- 3.1 主界面
- 四、实现步骤详解
- 4.1 环境准备
- 4.2 项目结构
- 4.3 核心实现流程
- 五、关键代码解析
- 5.1 剪贴板监控实现
- 5.2 历史记录数据结构
- 5.3 快捷键处理
- 5.4 主题切换实现
- 六、完整源码下载
- 七、拓展资料与扩展
- 7.1 项目拓展资料
- 7.2 可能的改进路线
- 7.3 实际应用价格
一、概述:为什么需要剪贴板历史管理
在日常职业和编程中,剪贴板是我们使用最频繁的功能其中一个。但Windows自带的剪贴板只能保存最近一次的内容,当我们需要回溯之前复制过的内容时,就显得力不从心。这篇文章小编将介绍怎样使用Python和PyQt5开发一个功能强大的剪贴板历史管理器,具有下面内容特点:
- 实时监控剪贴板变化,自动保存历史记录
- 支持快捷键快速粘贴历史内容(Ctrl+D+数字)
- 美观的GUI界面,支持多种主题切换
- 体系托盘运行,不占用任务栏空间
- 历史记录持久化保存,重启不丢失
- 内容搜索和分类管理功能
这个工具特别适合程序员、文字职业者和需要频繁复制粘贴的用户群体,能显著进步职业效率。
二、功能特性全解析
2.1 核心功能
- 剪贴板监控:实时检测剪贴板变化,自动保存新内容
- 历史记录管理:支持查看、复制、粘贴、删除历史记录
- 快速访问:通过快捷键(Ctrl+D+数字)快速粘贴最近9条记录
- 内容搜索:支持关键词搜索历史记录
- 数据持久化:自动保存历史记录到JSON文件
2.2 增强功能
多主题支持:提供默认、深色、蓝色、绿色、粉色五种主题
体系托盘集成:最小化到托盘,不影响职业区
智能去重:自动过滤连续重复内容
内容预览:列表显示内容简介,点击查看完整内容
可配置选项:
- 设置历史记录最大数量(10-500条)
- 启用/禁用快捷键
- 切换自动粘贴功能
- 设置开机启动(需额外配置)
三、效果展示
3.1 主界面
界面采用左右分栏设计:
- 左侧:历史记录列表,按时刻倒序排列
- 右侧:详情查看区和功能操作区
四、实现步骤详解
4.1 环境准备
pip install PyQt5 keyboard pyperclip
4.2 项目结构
clipboard_manager/
│── main.py 主程序
│── clipboard_history.json 历史记录存储文件
│── icons/ 图标资源
│ ├── icon16.png
│ ├── icon32.png
│ ├── icon48.png
│ └── icon256.png
4.3 核心实现流程
初始化应用:
- 创建QApplication和主窗口
- 设置体系托盘图标
- 加载历史记录文件
剪贴板监控:
self.clipboard_timer = QTimer(self) self.clipboard_timer.timeout.connect(self.check_clipboard) self.clipboard_timer.start(500) 每500ms检查一次
历史记录管理:
- 使用列表存储历史记录,每个记录包含内容、时刻戳和预览
- 实现添加、删除、清空等操作
- 自动限制最大记录数
快捷键处理:
keyboard.add_hotkey(f’ctrl+d+i}’, lambda i=i: self.paste_from_history(i-1))
UI构建:
- 使用QVBoxLayout和QHBoxLayout构建灵活布局
- 为各组件添加样式表美化界面
- 实现主题切换功能
五、关键代码解析
5.1 剪贴板监控实现
def check_clipboard(self): “””检查剪贴板内容是否变化””” current_clipboard = pyperclip.paste() if current_clipboard and (not self.history or current_clipboard != self.history[0][‘content’]): self.add_to_history(current_clipboard)
这段代码通过定时器定期检查剪贴板内容,当发现新内容且与最近记录不同时,将其添加到历史记录中。
5.2 历史记录数据结构
history_item = ‘content’: content, 完整内容 ‘timestamp’: datetime.now().strftime(“%Y-%m-%d %H:%M:%S”), 时刻戳 ‘preview’: content[:50] + (“…” if len(content) > 50 else “”) 预览}
每个历史记录项都包含这三个字段,便于显示和管理。
5.3 快捷键处理
def paste_from_history(self, index): “””通过快捷键粘贴指定索引的历史记录””” if 0 <= index < len(self.history): pyperclip.copy(self.history[index][‘content’]) if self.auto_paste: keyboard.send(‘ctrl+v’)
这段代码实现了通过快捷键快速粘贴历史记录的功能,同时支持自动粘贴模式。
5.4 主题切换实现
def change_theme(self, theme_name): “””更改应用程序主题””” if theme_name == “默认”: self.setStyleSheet(“”) elif theme_name == “深色”: self.set_dark_theme() 其他主题…
通过动态修改样式表(QSS)实现主题切换,每种主题定义了不同的颜色方案。
六、完整源码下载
import sysimport osimport jsonimport keyboardimport pyperclipfrom datetime import datetimefrom PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QListWidget, QPushButton, QLabel, QLineEdit, QTextEdit, QComboBox, QSpinBox, QCheckBox, QMessageBox, QSystemTrayIcon, QMenu, QAction, QStyle, QListWidgetItem)from PyQt5.QtCore import Qt, QTimer, QSizefrom PyQt5.QtGui import QIcon, QColor, QPalette, QFont, QBrushclass ClipboardHistoryApp(QMainWindow): def __init__(self): super().__init__() 初始化设置 self.history = [] self.max_history = 100 self.hotkeys_enabled = True self.auto_paste = True self.start_with_system = False self.history_file = “clipboard_history.json” 加载历史记录 self.load_history() 初始化UI self.init_ui() 设置体系托盘 self.init_system_tray() 设置定时器检查剪贴板变化 self.clipboard_timer = QTimer(self) self.clipboard_timer.timeout.connect(self.check_clipboard) self.clipboard_timer.start(500) 每500毫秒检查一次 注册全局快捷键 self.register_hotkeys() 设置窗口样式 self.set_window_style() def init_ui(self): “””初始化用户界面””” self.setWindowTitle(“剪贴板历史管理器”) self.setGeometry(100, 100, 800, 600) 主窗口部件 main_widget = QWidget() self.setCentralWidget(main_widget) 主布局 main_layout = QHBoxLayout() main_widget.setLayout(main_layout) 左侧面板 – 历史记录列表 left_panel = QWidget() left_layout = QVBoxLayout() left_panel.setLayout(left_layout) self.history_list = QListWidget() self.history_list.setStyleSheet(“”” QListWidget background-color: f0f0f0; border: 1px solid ccc; border-radius: 5px; padding: 5px; } QListWidget::item padding: 8px; border-bottom: 1px solid ddd; } QListWidget::item:hover background-color: e0e0e0; } QListWidget::item:selected background-color: 4CAF50; color: white; } “””) self.history_list.itemClicked.connect(self.show_selected_item) left_layout.addWidget(QLabel(“剪贴板历史记录:”)) left_layout.addWidget(self.history_list) 右侧面板 – 详情和设置 right_panel = QWidget() right_layout = QVBoxLayout() right_panel.setLayout(right_layout) 详情区域 detail_group = QWidget() detail_layout = QVBoxLayout() detail_group.setLayout(detail_layout) self.detail_text = QTextEdit() self.detail_text.setReadOnly(True) self.detail_text.setStyleSheet(“”” QTextEdit background-color: f9f9f9; border: 1px solid ccc; border-radius: 5px; padding: 10px; min-height: 150px; } “””) detail_layout.addWidget(QLabel(“内容详情:”)) detail_layout.addWidget(self.detail_text) 操作按钮 button_group = QWidget() button_layout = QHBoxLayout() button_group.setLayout(button_layout) self.copy_btn = QPushButton(“复制选中项”) self.copy_btn.setStyleSheet(“”” QPushButton background-color: 4CAF50; color: white; border: none; padding: 8px; border-radius: 4px; } QPushButton:hover background-color: 45a049; } “””) self.copy_btn.clicked.connect(self.copy_selected) self.paste_btn = QPushButton(“粘贴选中项”) self.paste_btn.setStyleSheet(“”” QPushButton background-color: 008CBA; color: white; border: none; padding: 8px; border-radius: 4px; } QPushButton:hover background-color: 0077A3; } “””) self.paste_btn.clicked.connect(self.paste_selected) self.delete_btn = QPushButton(“删除选中项”) self.delete_btn.setStyleSheet(“”” QPushButton background-color: f44336; color: white; border: none; padding: 8px; border-radius: 4px; } QPushButton:hover background-color: d32f2f; } “””) self.delete_btn.clicked.connect(self.delete_selected) 新增清空历史按钮 self.clear_btn = QPushButton(“清空历史”) self.clear_btn.setStyleSheet(“”” QPushButton background-color: ff9800; color: white; border: none; padding: 8px; border-radius: 4px; } QPushButton:hover background-color: e68a00; } “””) self.clear_btn.clicked.connect(self.clear_history) button_layout.addWidget(self.copy_btn) button_layout.addWidget(self.paste_btn) button_layout.addWidget(self.delete_btn) button_layout.addWidget(self.clear_btn) 搜索区域 search_group = QWidget() search_layout = QHBoxLayout() search_group.setLayout(search_layout) self.search_input = QLineEdit() self.search_input.setPlaceholderText(“搜索剪贴板历史…”) self.search_input.textChanged.connect(self.search_history) self.search_input.setStyleSheet(“”” QLineEdit padding: 8px; border: 1px solid ccc; border-radius: 4px; } “””) search_btn = QPushButton(“搜索”) search_btn.setStyleSheet(“”” QPushButton background-color: 555; color: white; border: none; padding: 8px 15px; border-radius: 4px; margin-left: 5px; } QPushButton:hover background-color: 444; } “””) search_btn.clicked.connect(self.search_history) search_layout.addWidget(self.search_input) search_layout.addWidget(search_btn) 设置区域 settings_group = QWidget() settings_layout = QVBoxLayout() settings_group.setLayout(settings_layout) settings_layout.addWidget(QLabel(“设置:”)) 历史记录限制 history_limit_layout = QHBoxLayout() history_limit_layout.addWidget(QLabel(“最大历史记录数:”)) self.history_limit_spin = QSpinBox() self.history_limit_spin.setRange(10, 500) self.history_limit_spin.setValue(self.max_history) self.history_limit_spin.valueChanged.connect(self.update_history_limit) history_limit_layout.addWidget(self.history_limit_spin) settings_layout.addLayout(history_limit_layout) 快捷键设置 hotkey_layout = QHBoxLayout() self.hotkey_checkbox = QCheckBox(“启用快捷键 (Ctrl+D+数字)”) self.hotkey_checkbox.setChecked(self.hotkeys_enabled) self.hotkey_checkbox.stateChanged.connect(self.toggle_hotkeys) hotkey_layout.addWidget(self.hotkey_checkbox) settings_layout.addLayout(hotkey_layout) 自动粘贴设置 auto_paste_layout = QHBoxLayout() self.auto_paste_checkbox = QCheckBox(“使用快捷键时自动粘贴”) self.auto_paste_checkbox.setChecked(self.auto_paste) self.auto_paste_checkbox.stateChanged.connect(self.toggle_auto_paste) auto_paste_layout.addWidget(self.auto_paste_checkbox) settings_layout.addLayout(auto_paste_layout) 开机启动设置 startup_layout = QHBoxLayout() self.startup_checkbox = QCheckBox(“开机自动启动”) self.startup_checkbox.setChecked(self.start_with_system) self.startup_checkbox.stateChanged.connect(self.toggle_start_with_system) startup_layout.addWidget(self.startup_checkbox) settings_layout.addLayout(startup_layout) 主题选择 theme_layout = QHBoxLayout() theme_layout.addWidget(QLabel(“主题:”)) self.theme_combo = QComboBox() self.theme_combo.addItems([“默认”, “深色”, “蓝色”, “绿色”, “粉色”]) self.theme_combo.currentTextChanged.connect(self.change_theme) theme_layout.addWidget(self.theme_combo) settings_layout.addLayout(theme_layout) 添加所有右侧组件 right_layout.addWidget(detail_group) right_layout.addWidget(button_group) right_layout.addWidget(search_group) right_layout.addWidget(settings_group) 添加左右面板到主布局 main_layout.addWidget(left_panel, 70) main_layout.addWidget(right_panel, 30) 更新历史记录列表 self.update_history_list() def set_window_style(self): “””设置窗口样式””” self.setStyleSheet(“”” QMainWindow background-color: f5f5f5; } QLabel font-weight: bold; color: 333; } QGroupBox border: 1px solid ddd; border-radius: 5px; margin-top: 10px; padding-top: 15px; } QGroupBox::title subcontrol-origin: margin; left: 10px; padding: 0 3px; } “””) def init_system_tray(self): “””初始化体系托盘””” self.tray_icon = QSystemTrayIcon(self) self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon)) tray_menu = QMenu() show_action = QAction(“显示”, self) show_action.triggered.connect(self.show) tray_menu.addAction(show_action) hide_action = QAction(“隐藏”, self) hide_action.triggered.connect(self.hide) tray_menu.addAction(hide_action) quit_action = QAction(“退出”, self) quit_action.triggered.connect(self.quit_app) tray_menu.addAction(quit_action) self.tray_icon.setContextMenu(tray_menu) self.tray_icon.show() self.tray_icon.activated.connect(self.tray_icon_activated) def tray_icon_activated(self, reason): “””体系托盘图标被激活时的处理””” if reason == QSystemTrayIcon.DoubleClick: self.show() def closeEvent(self, event): “””重写关闭事件,最小化到托盘””” event.ignore() self.hide() self.tray_icon.showMessage( “剪贴板历史管理器”, “程序已最小化到体系托盘”, QSystemTrayIcon.Information, 2000 ) def register_hotkeys(self): “””注册全局快捷键””” if self.hotkeys_enabled: try: 注册Ctrl+D+数字1-9的快捷键 for i in range(1, 10): keyboard.add_hotkey(f’ctrl+d+i}’, lambda i=i: self.paste_from_history(i-1)) except Exception as e: print(f”注册快捷键失败: e}”) def unregister_hotkeys(self): “””取消注册全局快捷键””” try: keyboard.unhook_all_hotkeys() except Exception as e: print(f”取消注册快捷键失败: e}”) def toggle_hotkeys(self, state): “””切换快捷键启用情形””” self.hotkeys_enabled = state == Qt.Checked if self.hotkeys_enabled: self.register_hotkeys() else: self.unregister_hotkeys() def toggle_auto_paste(self, state): “””切换自动粘贴设置””” self.auto_paste = state == Qt.Checked def toggle_start_with_system(self, state): “””切换开机启动设置””” self.start_with_system = state == Qt.Checked 这里需要实现实际的开机启动设置逻辑 QMessageBox.information(self, “提示”, “开机启动功能需要根据操作体系进行额外配置”) def update_history_limit(self, value): “””更新历史记录最大数量””” self.max_history = value 如果当前历史记录超过新限制,截断 if len(self.history) > self.max_history: self.history = self.history[:self.max_history] self.update_history_list() def change_theme(self, theme_name): “””更改应用程序主题””” if theme_name == “默认”: self.setStyleSheet(“”) elif theme_name == “深色”: self.set_dark_theme() elif theme_name == “蓝色”: self.set_blue_theme() elif theme_name == “绿色”: self.set_green_theme() elif theme_name == “粉色”: self.set_pink_theme() def set_dark_theme(self): “””设置深色主题””” dark_style = “”” QMainWindow background-color: 333; } QListWidget background-color: 444; color: eee; border: 1px solid 555; } QListWidget::item border-bottom: 1px solid 555; } QListWidget::item:hover background-color: 555; } QListWidget::item:selected background-color: 4CAF50; } QTextEdit, QLineEdit background-color: 444; color: eee; border: 1px solid 555; } QPushButton background-color: 555; color: white; border: none; } QPushButton:hover background-color: 666; } QLabel color: eee; } QSpinBox, QComboBox background-color: 444; color: eee; border: 1px solid 555; } “”” self.setStyleSheet(dark_style) def set_blue_theme(self): “””设置蓝色主题””” blue_style = “”” QMainWindow background-color: e6f2ff; } QListWidget background-color: f0f7ff; border: 1px solid b3d1ff; } QListWidget::item:hover background-color: d9e6ff; } QListWidget::item:selected background-color: 4d94ff; color: white; } QPushButton background-color: 4d94ff; color: white; } QPushButton:hover background-color: 3d84ef; } “”” self.setStyleSheet(blue_style) def set_green_theme(self): “””设置绿色主题””” green_style = “”” QMainWindow background-color: e6ffe6; } QListWidget background-color: f0fff0; border: 1px solid b3e6b3; } QListWidget::item:hover background-color: d9ffd9; } QListWidget::item:selected background-color: 4CAF50; color: white; } QPushButton background-color: 4CAF50; color: white; } QPushButton:hover background-color: 45a049; } “”” self.setStyleSheet(green_style) def set_pink_theme(self): “””设置粉色主题””” pink_style = “”” QMainWindow background-color: ffe6f2; } QListWidget background-color: fff0f7; border: 1px solid ffb3d9; } QListWidget::item:hover background-color: ffd9ec; } QListWidget::item:selected background-color: ff66b3; color: white; } QPushButton background-color: ff66b3; color: white; } QPushButton:hover background-color: ff4da6; } “”” self.setStyleSheet(pink_style) def check_clipboard(self): “””检查剪贴板内容是否变化””” current_clipboard = pyperclip.paste() if current_clipboard and (not self.history or current_clipboard != self.history[0][‘content’]): 添加到历史记录 self.add_to_history(current_clipboard) def add_to_history(self, content): “””添加内容到历史记录””” if not content.strip():