基于Python开发一个桌面便签工具
作者:小庄-Python办公
这篇文章主要为大家详细介绍了如何基于Python开发一个桌面便签工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
前言
一个功能丰富的桌面置顶便签小工具,使用Python和tkinter开发。
功能特点
- 窗口置顶: 便签窗口始终保持在桌面最前端
- 自动保存: 程序关闭时自动保存内容和配置
- 字体自定义: 支持修改字体类型和大小
- 颜色主题: 可自定义背景色和文字颜色
- 文件操作: 支持新建、打开、保存文本文件
- 实时时间: 显示当前日期和时间
- 快捷键支持: 常用操作的键盘快捷键
使用方法
方法:直接运行Python文件
python sticky_notes.py
快捷键
Ctrl + S: 保存文件
Ctrl + N: 新建便签
Ctrl + O: 打开文件
菜单功能
文件菜单
- 新建: 清空当前内容,创建新便签
- 打开: 打开已保存的文本文件
- 保存: 将当前内容保存为文件
- 退出: 关闭程序
设置菜单
- 字体设置: 修改字体类型和大小
- 颜色设置: 自定义背景色和文字颜色
- 置顶设置: 开启/关闭窗口置顶功能
帮助菜单
关于: 查看程序信息和使用说明
工具栏按钮
新建: 创建新便签
保存: 保存当前内容
清空: 清空所有文本内容
自动保存功能
程序会自动保存以下内容:
- 便签文本内容(保存在 sticky_notes_content.txt)
- 程序配置设置(保存在 sticky_notes_config.json)
- 窗口位置和大小
- 字体和颜色设置
系统要求
Python 3.6 或更高版本
tkinter 库(Python标准库,通常已包含)
文件说明
- sticky_notes.py: 主程序文件
- run.bat: Windows启动脚本
- sticky_notes_config.json: 配置文件(自动生成)
- sticky_notes_content.txt: 内容文件(自动生成)
注意事项
- 首次运行时会创建配置文件和内容文件
- 程序关闭时会自动保存当前状态
- 如需重置所有设置,可删除配置文件重新启动程序
- 支持中文显示和输入
故障排除
如果程序无法启动,请检查:
- 是否已正确安装Python
- Python是否已添加到系统PATH环境变量
- 是否有足够的权限在当前目录创建文件
完整代码
import tkinter as tk from tkinter import messagebox, filedialog, colorchooser, font import json import os from datetime import datetime class StickyNoteEnhanced: def __init__(self): self.root = tk.Tk() self.root.title("桌面便签工具 Enhanced") self.root.geometry("450x350") self.root.configure(bg='#FFFACD') # 设置窗口置顶 self.root.attributes('-topmost', True) # 配置文件路径 self.config_file = "sticky_notes_config.json" self.notes_dir = "saved_notes" # 创建保存目录 if not os.path.exists(self.notes_dir): os.makedirs(self.notes_dir) # 默认配置 self.config = { 'font_size': 12, 'font_family': 'Microsoft YaHei', 'bg_color': '#FFFACD', 'text_color': '#000000', 'window_size': '450x350', 'window_position': '+100+100', 'always_on_top': True, 'transparency': 1.0, 'auto_save': True } # 加载配置 self.load_config() # 创建界面 self.create_widgets() # 加载保存的内容 self.load_content() # 绑定关闭事件 self.root.protocol("WM_DELETE_WINDOW", self.on_closing) # 自动保存定时器 if self.config['auto_save']: self.auto_save_timer() def create_widgets(self): """创建界面组件""" # 创建菜单栏 menubar = tk.Menu(self.root) self.root.config(menu=menubar) # 文件菜单 file_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="文件", menu=file_menu) file_menu.add_command(label="新建", command=self.new_note) file_menu.add_command(label="打开", command=self.open_file) file_menu.add_command(label="保存", command=self.save_file) file_menu.add_command(label="另存为", command=self.save_as_file) file_menu.add_separator() file_menu.add_command(label="导入", command=self.import_note) file_menu.add_command(label="导出", command=self.export_note) file_menu.add_separator() file_menu.add_command(label="退出", command=self.on_closing) # 编辑菜单 edit_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="编辑", menu=edit_menu) edit_menu.add_command(label="撤销", command=self.undo) edit_menu.add_command(label="重做", command=self.redo) edit_menu.add_separator() edit_menu.add_command(label="剪切", command=self.cut_text) edit_menu.add_command(label="复制", command=self.copy_text) edit_menu.add_command(label="粘贴", command=self.paste_text) edit_menu.add_separator() edit_menu.add_command(label="全选", command=self.select_all) edit_menu.add_command(label="查找", command=self.find_text) # 设置菜单 settings_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="设置", menu=settings_menu) settings_menu.add_command(label="字体设置", command=self.font_settings) settings_menu.add_command(label="颜色设置", command=self.color_settings) settings_menu.add_command(label="透明度设置", command=self.transparency_settings) settings_menu.add_command(label="置顶设置", command=self.toggle_topmost) settings_menu.add_command(label="自动保存", command=self.toggle_auto_save) # 帮助菜单 help_menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="帮助", menu=help_menu) help_menu.add_command(label="快捷键", command=self.show_shortcuts) help_menu.add_command(label="关于", command=self.show_about) # 创建工具栏 toolbar = tk.Frame(self.root, bg=self.config['bg_color']) toolbar.pack(fill=tk.X, padx=5, pady=2) # 工具栏按钮 tk.Button(toolbar, text="新建", command=self.new_note, width=6).pack(side=tk.LEFT, padx=2) tk.Button(toolbar, text="打开", command=self.open_file, width=6).pack(side=tk.LEFT, padx=2) tk.Button(toolbar, text="保存", command=self.save_file, width=6).pack(side=tk.LEFT, padx=2) tk.Button(toolbar, text="清空", command=self.clear_text, width=6).pack(side=tk.LEFT, padx=2) # 分隔符 tk.Frame(toolbar, width=2, bg='gray').pack(side=tk.LEFT, fill=tk.Y, padx=5) # 字体大小调节 tk.Label(toolbar, text="字号:", bg=self.config['bg_color']).pack(side=tk.LEFT, padx=2) self.font_size_var = tk.StringVar(value=str(self.config['font_size'])) font_size_combo = tk.Spinbox(toolbar, from_=8, to=72, width=5, textvariable=self.font_size_var, command=self.change_font_size) font_size_combo.pack(side=tk.LEFT, padx=2) # 时间标签 self.time_label = tk.Label(toolbar, text="", bg=self.config['bg_color'], fg=self.config['text_color']) self.time_label.pack(side=tk.RIGHT, padx=5) self.update_time() # 创建文本编辑区域 text_frame = tk.Frame(self.root) text_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=5) # 文本框 self.text_area = tk.Text( text_frame, font=(self.config['font_family'], self.config['font_size']), bg=self.config['bg_color'], fg=self.config['text_color'], wrap=tk.WORD, undo=True, maxundo=50 ) # 滚动条 scrollbar = tk.Scrollbar(text_frame) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) self.text_area.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) self.text_area.config(yscrollcommand=scrollbar.set) scrollbar.config(command=self.text_area.yview) # 状态栏 status_frame = tk.Frame(self.root) status_frame.pack(side=tk.BOTTOM, fill=tk.X) self.status_bar = tk.Label( status_frame, text="就绪", relief=tk.SUNKEN, anchor=tk.W, bg=self.config['bg_color'], fg=self.config['text_color'] ) self.status_bar.pack(side=tk.LEFT, fill=tk.X, expand=True) # 字符统计标签 self.char_count_label = tk.Label( status_frame, text="字符: 0", relief=tk.SUNKEN, bg=self.config['bg_color'], fg=self.config['text_color'] ) self.char_count_label.pack(side=tk.RIGHT, padx=5) # 绑定事件 self.bind_events() def bind_events(self): """绑定快捷键和事件""" # 快捷键 self.root.bind('<Control-s>', lambda e: self.save_file()) self.root.bind('<Control-n>', lambda e: self.new_note()) self.root.bind('<Control-o>', lambda e: self.open_file()) self.root.bind('<Control-z>', lambda e: self.undo()) self.root.bind('<Control-y>', lambda e: self.redo()) self.root.bind('<Control-a>', lambda e: self.select_all()) self.root.bind('<Control-f>', lambda e: self.find_text()) self.root.bind('<Control-plus>', lambda e: self.increase_font()) self.root.bind('<Control-minus>', lambda e: self.decrease_font()) # 文本变化事件 self.text_area.bind('<KeyRelease>', self.on_text_change) self.text_area.bind('<Button-1>', self.on_text_change) def update_time(self): """更新时间显示""" current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.time_label.config(text=current_time) self.root.after(1000, self.update_time) def on_text_change(self, event=None): """文本变化时的处理""" content = self.text_area.get(1.0, tk.END) char_count = len(content) - 1 # 减去末尾的换行符 self.char_count_label.config(text=f"字符: {char_count}") def change_font_size(self): """改变字体大小""" try: new_size = int(self.font_size_var.get()) self.config['font_size'] = new_size self.text_area.config(font=(self.config['font_family'], new_size)) self.save_config() except ValueError: pass def increase_font(self): """增大字体""" current_size = self.config['font_size'] if current_size < 72: self.config['font_size'] = current_size + 1 self.font_size_var.set(str(self.config['font_size'])) self.text_area.config(font=(self.config['font_family'], self.config['font_size'])) self.save_config() def decrease_font(self): """减小字体""" current_size = self.config['font_size'] if current_size > 8: self.config['font_size'] = current_size - 1 self.font_size_var.set(str(self.config['font_size'])) self.text_area.config(font=(self.config['font_family'], self.config['font_size'])) self.save_config() def new_note(self): """新建便签""" if self.text_area.get(1.0, tk.END).strip(): if messagebox.askyesno("新建", "当前内容未保存,是否继续?"): self.text_area.delete(1.0, tk.END) self.status_bar.config(text="新建便签") else: self.text_area.delete(1.0, tk.END) self.status_bar.config(text="新建便签") def save_file(self): """保存文件""" try: content = self.text_area.get(1.0, tk.END) if not hasattr(self, 'current_file') or not self.current_file: self.save_as_file() return with open(self.current_file, 'w', encoding='utf-8') as f: f.write(content) self.status_bar.config(text=f"已保存: {os.path.basename(self.current_file)}") except Exception as e: messagebox.showerror("错误", f"保存失败: {str(e)}") def save_as_file(self): """另存为文件""" try: content = self.text_area.get(1.0, tk.END) filename = filedialog.asksaveasfilename( defaultextension=".txt", filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if filename: with open(filename, 'w', encoding='utf-8') as f: f.write(content) self.current_file = filename self.status_bar.config(text=f"已保存: {os.path.basename(filename)}") messagebox.showinfo("保存", "文件保存成功!") except Exception as e: messagebox.showerror("错误", f"保存失败: {str(e)}") def open_file(self): """打开文件""" try: filename = filedialog.askopenfilename( filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")] ) if filename: with open(filename, 'r', encoding='utf-8') as f: content = f.read() self.text_area.delete(1.0, tk.END) self.text_area.insert(1.0, content) self.current_file = filename self.status_bar.config(text=f"已打开: {os.path.basename(filename)}") except Exception as e: messagebox.showerror("错误", f"打开失败: {str(e)}") def import_note(self): """导入便签""" self.open_file() def export_note(self): """导出便签""" self.save_as_file() def clear_text(self): """清空文本""" if messagebox.askyesno("清空", "确定要清空所有内容吗?"): self.text_area.delete(1.0, tk.END) self.status_bar.config(text="已清空内容") def undo(self): """撤销""" try: self.text_area.edit_undo() except tk.TclError: pass def redo(self): """重做""" try: self.text_area.edit_redo() except tk.TclError: pass def cut_text(self): """剪切""" try: self.text_area.event_generate("<<Cut>>") except: pass def copy_text(self): """复制""" try: self.text_area.event_generate("<<Copy>>") except: pass def paste_text(self): """粘贴""" try: self.text_area.event_generate("<<Paste>>") except: pass def select_all(self): """全选""" self.text_area.tag_add(tk.SEL, "1.0", tk.END) self.text_area.mark_set(tk.INSERT, "1.0") self.text_area.see(tk.INSERT) return 'break' def find_text(self): """查找文本""" find_window = tk.Toplevel(self.root) find_window.title("查找") find_window.geometry("300x100") find_window.attributes('-topmost', True) tk.Label(find_window, text="查找内容:").pack(pady=5) search_var = tk.StringVar() search_entry = tk.Entry(find_window, textvariable=search_var, width=30) search_entry.pack(pady=5) search_entry.focus() def do_find(): search_text = search_var.get() if search_text: start_pos = self.text_area.search(search_text, tk.INSERT, tk.END) if start_pos: end_pos = f"{start_pos}+{len(search_text)}c" self.text_area.tag_remove(tk.SEL, "1.0", tk.END) self.text_area.tag_add(tk.SEL, start_pos, end_pos) self.text_area.mark_set(tk.INSERT, end_pos) self.text_area.see(start_pos) else: messagebox.showinfo("查找", "未找到指定内容") tk.Button(find_window, text="查找", command=do_find).pack(pady=5) search_entry.bind('<Return>', lambda e: do_find()) def font_settings(self): """字体设置""" font_window = tk.Toplevel(self.root) font_window.title("字体设置") font_window.geometry("350x250") font_window.attributes('-topmost', True) # 字体族 tk.Label(font_window, text="字体:").pack(pady=5) font_var = tk.StringVar(value=self.config['font_family']) font_families = list(font.families()) font_combo = tk.Listbox(font_window, height=6) for family in font_families: font_combo.insert(tk.END, family) font_combo.pack(pady=5, fill=tk.BOTH, expand=True) # 设置当前选中的字体 try: current_index = font_families.index(self.config['font_family']) font_combo.selection_set(current_index) font_combo.see(current_index) except ValueError: pass # 字体大小 size_frame = tk.Frame(font_window) size_frame.pack(pady=5) tk.Label(size_frame, text="大小:").pack(side=tk.LEFT) size_var = tk.IntVar(value=self.config['font_size']) size_spin = tk.Spinbox(size_frame, from_=8, to=72, textvariable=size_var, width=10) size_spin.pack(side=tk.LEFT, padx=5) def apply_font(): selection = font_combo.curselection() if selection: selected_font = font_families[selection[0]] self.config['font_family'] = selected_font self.config['font_size'] = size_var.get() self.text_area.config(font=(self.config['font_family'], self.config['font_size'])) self.font_size_var.set(str(self.config['font_size'])) self.save_config() font_window.destroy() button_frame = tk.Frame(font_window) button_frame.pack(pady=10) tk.Button(button_frame, text="应用", command=apply_font).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="取消", command=font_window.destroy).pack(side=tk.LEFT, padx=5) def color_settings(self): """颜色设置""" color_window = tk.Toplevel(self.root) color_window.title("颜色设置") color_window.geometry("250x200") color_window.attributes('-topmost', True) def choose_bg_color(): color = colorchooser.askcolor(title="选择背景颜色", initialcolor=self.config['bg_color']) if color[1]: self.config['bg_color'] = color[1] self.apply_colors() def choose_text_color(): color = colorchooser.askcolor(title="选择文字颜色", initialcolor=self.config['text_color']) if color[1]: self.config['text_color'] = color[1] self.apply_colors() tk.Button(color_window, text="背景颜色", command=choose_bg_color, width=15).pack(pady=10) tk.Button(color_window, text="文字颜色", command=choose_text_color, width=15).pack(pady=10) def reset_colors(): self.config['bg_color'] = '#FFFACD' self.config['text_color'] = '#000000' self.apply_colors() tk.Button(color_window, text="恢复默认", command=reset_colors, width=15).pack(pady=10) tk.Button(color_window, text="关闭", command=color_window.destroy, width=15).pack(pady=10) def transparency_settings(self): """透明度设置""" trans_window = tk.Toplevel(self.root) trans_window.title("透明度设置") trans_window.geometry("300x150") trans_window.attributes('-topmost', True) tk.Label(trans_window, text="透明度 (0.1-1.0):").pack(pady=10) trans_var = tk.DoubleVar(value=self.config['transparency']) trans_scale = tk.Scale(trans_window, from_=0.1, to=1.0, resolution=0.1, orient=tk.HORIZONTAL, variable=trans_var, length=200) trans_scale.pack(pady=10) def apply_transparency(): self.config['transparency'] = trans_var.get() self.root.attributes('-alpha', self.config['transparency']) self.save_config() trans_window.destroy() def preview_transparency(): self.root.attributes('-alpha', trans_var.get()) trans_scale.config(command=lambda x: preview_transparency()) button_frame = tk.Frame(trans_window) button_frame.pack(pady=10) tk.Button(button_frame, text="应用", command=apply_transparency).pack(side=tk.LEFT, padx=5) tk.Button(button_frame, text="取消", command=trans_window.destroy).pack(side=tk.LEFT, padx=5) def apply_colors(self): """应用颜色设置""" self.root.configure(bg=self.config['bg_color']) self.text_area.configure(bg=self.config['bg_color'], fg=self.config['text_color']) self.time_label.configure(bg=self.config['bg_color'], fg=self.config['text_color']) self.status_bar.configure(bg=self.config['bg_color'], fg=self.config['text_color']) self.char_count_label.configure(bg=self.config['bg_color'], fg=self.config['text_color']) self.save_config() def toggle_topmost(self): """切换置顶状态""" self.config['always_on_top'] = not self.config['always_on_top'] self.root.attributes('-topmost', self.config['always_on_top']) status = "已开启" if self.config['always_on_top'] else "已关闭" self.status_bar.config(text=f"窗口置顶 {status}") self.save_config() def toggle_auto_save(self): """切换自动保存""" self.config['auto_save'] = not self.config['auto_save'] status = "已开启" if self.config['auto_save'] else "已关闭" self.status_bar.config(text=f"自动保存 {status}") self.save_config() if self.config['auto_save']: self.auto_save_timer() def auto_save_timer(self): """自动保存定时器""" if self.config['auto_save']: self.save_content() self.root.after(30000, self.auto_save_timer) # 30秒自动保存 def show_shortcuts(self): """显示快捷键""" shortcuts_text = """ 快捷键列表: Ctrl+N: 新建便签 Ctrl+O: 打开文件 Ctrl+S: 保存文件 Ctrl+Z: 撤销 Ctrl+Y: 重做 Ctrl+A: 全选 Ctrl+F: 查找 Ctrl+Plus: 增大字体 Ctrl+Minus: 减小字体 """ messagebox.showinfo("快捷键", shortcuts_text) def show_about(self): """显示关于信息""" about_text = """ 桌面便签工具 Enhanced v2.0 功能特点: • 窗口置顶显示 • 自动保存配置和内容 • 支持字体和颜色自定义 • 支持透明度调节 • 支持文件保存和打开 • 实时时间和字符统计 • 丰富的编辑功能 • 快捷键支持 作者:AI助手 版本:2.0 """ messagebox.showinfo("关于", about_text) def load_config(self): """加载配置""" try: if os.path.exists(self.config_file): with open(self.config_file, 'r', encoding='utf-8') as f: saved_config = json.load(f) self.config.update(saved_config) except Exception as e: print(f"加载配置失败: {e}") def save_config(self): """保存配置""" try: # 保存当前窗口位置和大小 geometry = self.root.geometry() if '+' in geometry: self.config['window_size'] = geometry.split('+')[0] self.config['window_position'] = '+' + '+'.join(geometry.split('+')[1:]) with open(self.config_file, 'w', encoding='utf-8') as f: json.dump(self.config, f, ensure_ascii=False, indent=2) except Exception as e: print(f"保存配置失败: {e}") def load_content(self): """加载保存的内容""" try: content_file = "sticky_notes_content.txt" if os.path.exists(content_file): with open(content_file, 'r', encoding='utf-8') as f: content = f.read() self.text_area.insert(1.0, content) except Exception as e: print(f"加载内容失败: {e}") def save_content(self): """保存当前内容""" try: content = self.text_area.get(1.0, tk.END) content_file = "sticky_notes_content.txt" with open(content_file, 'w', encoding='utf-8') as f: f.write(content) except Exception as e: print(f"保存内容失败: {e}") def on_closing(self): """关闭程序时的处理""" self.save_content() self.save_config() self.root.destroy() def run(self): """运行程序""" # 应用保存的窗口设置 geometry = self.config['window_size'] + self.config['window_position'] self.root.geometry(geometry) self.root.attributes('-topmost', self.config['always_on_top']) self.root.attributes('-alpha', self.config['transparency']) # 应用颜色设置 self.apply_colors() self.root.mainloop() if __name__ == "__main__": app = StickyNoteEnhanced() app.run()
效果图
到此这篇关于基于Python开发一个桌面便签工具的文章就介绍到这了,更多相关Python便签内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!