基于Python编写一个win10桌面便签工具

我来为您创建一个功能完整的Windows 10桌面便签工具。这个工具将包含创建、编辑、删除、置顶便签等功能,并具有现代化的UI设计。

图片[1]_基于Python编写一个win10桌面便签工具_知途无界
import tkinter as tk
from tkinter import ttk, colorchooser, messagebox, font
import json
import os
from datetime import datetime
import uuid

class StickyNote:
    def __init__(self, root):
        self.root = root
        self.root.title("桌面便签工具")
        self.root.geometry("400x500")
        self.root.configure(bg='#f0f0f0')
        
        # 便签数据存储文件
        self.data_file = "sticky_notes.json"
        self.notes = {}
        self.current_note_id = None
        
        # 默认便签颜色
        self.colors = {
            'yellow': '#fff380',
            'pink': '#ffb3d9',
            'blue': '#b3d9ff',
            'green': '#b3ffb3',
            'purple': '#e6b3ff',
            'orange': '#ffcc99'
        }
        
        self.setup_ui()
        self.load_notes()
        
    def setup_ui(self):
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        
        # 标题
        title_label = ttk.Label(main_frame, text="📝 桌面便签工具", 
                               font=('Arial', 16, 'bold'))
        title_label.grid(row=0, column=0, columnspan=3, pady=(0, 20))
        
        # 创建新便签按钮
        create_btn = ttk.Button(main_frame, text="+ 新建便签", 
                               command=self.create_new_note)
        create_btn.grid(row=1, column=0, columnspan=3, pady=(0, 10), sticky='ew')
        
        # 便签列表框架
        list_frame = ttk.LabelFrame(main_frame, text="我的便签", padding="10")
        list_frame.grid(row=2, column=0, columnspan=3, sticky='nsew', pady=(0, 10))
        
        # 便签列表
        self.note_listbox = tk.Listbox(list_frame, height=8, font=('Arial', 10))
        self.note_listbox.pack(fill='both', expand=True)
        self.note_listbox.bind('<<ListboxSelect>>', self.on_note_select)
        
        # 删除按钮
        delete_btn = ttk.Button(list_frame, text="删除选中便签", 
                               command=self.delete_selected_note)
        delete_btn.pack(pady=(10, 0))
        
        # 便签编辑器框架
        editor_frame = ttk.LabelFrame(main_frame, text="便签编辑器", padding="10")
        editor_frame.grid(row=3, column=0, columnspan=3, sticky='nsew', pady=(0, 10))
        
        # 便签标题
        ttk.Label(editor_frame, text="标题:").grid(row=0, column=0, sticky='w', pady=(0, 5))
        self.title_entry = ttk.Entry(editor_frame, font=('Arial', 11))
        self.title_entry.grid(row=1, column=0, columnspan=3, sticky='ew', pady=(0, 10))
        
        # 字体设置
        font_frame = ttk.Frame(editor_frame)
        font_frame.grid(row=2, column=0, columnspan=3, sticky='ew', pady=(0, 10))
        
        ttk.Label(font_frame, text="字体大小:").pack(side='left')
        self.font_size_var = tk.StringVar(value="12")
        font_size_combo = ttk.Combobox(font_frame, textvariable=self.font_size_var,
                                      values=["10", "12", "14", "16", "18", "20"],
                                      width=5, state="readonly")
        font_size_combo.pack(side='left', padx=(10, 20))
        
        ttk.Label(font_frame, text="颜色:").pack(side='left')
        self.color_var = tk.StringVar(value="yellow")
        color_combo = ttk.Combobox(font_frame, textvariable=self.color_var,
                                  values=list(self.colors.keys()),
                                  width=10, state="readonly")
        color_combo.pack(side='left', padx=(10, 0))
        
        # 便签内容
        ttk.Label(editor_frame, text="内容:").grid(row=3, column=0, sticky='nw', pady=(0, 5))
        self.content_text = tk.Text(editor_frame, height=8, wrap='word', 
                                   font=('Arial', 12), undo=True)
        content_scrollbar = ttk.Scrollbar(editor_frame, orient='vertical', 
                                         command=self.content_text.yview)
        self.content_text.configure(yscrollcommand=content_scrollbar.set)
        self.content_text.grid(row=4, column=0, columnspan=3, sticky='nsew', pady=(0, 10))
        content_scrollbar.grid(row=4, column=3, sticky='ns')
        
        # 按钮框架
        button_frame = ttk.Frame(editor_frame)
        button_frame.grid(row=5, column=0, columnspan=3, pady=(0, 10))
        
        save_btn = ttk.Button(button_frame, text="💾 保存便签", 
                             command=self.save_current_note)
        save_btn.pack(side='left', padx=(0, 10))
        
        pin_btn = ttk.Button(button_frame, text="📌 置顶显示", 
                            command=self.pin_note)
        pin_btn.pack(side='left', padx=(0, 10))
        
        clear_btn = ttk.Button(button_frame, text="🗑️ 清空内容", 
                              command=self.clear_editor)
        clear_btn.pack(side='left')
        
        # 配置网格权重
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(2, weight=1)
        main_frame.rowconfigure(3, weight=2)
        editor_frame.columnconfigure(0, weight=1)
        editor_frame.rowconfigure(4, weight=1)
        
        # 状态栏
        self.status_var = tk.StringVar(value="就绪")
        status_bar = ttk.Label(main_frame, textvariable=self.status_var, 
                              relief='sunken', anchor='w')
        status_bar.grid(row=4, column=0, columnspan=3, sticky='ew', pady=(10, 0))
        
    def create_new_note(self):
        """创建新便签"""
        note_id = str(uuid.uuid4())
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
        
        self.notes[note_id] = {
            'id': note_id,
            'title': f'新便签 {len(self.notes) + 1}',
            'content': '',
            'color': 'yellow',
            'font_size': 12,
            'created_time': current_time,
            'modified_time': current_time,
            'pinned': False
        }
        
        self.current_note_id = note_id
        self.update_note_list()
        self.load_note_to_editor(note_id)
        self.status_var.set(f"已创建新便签 - {current_time}")
        
    def update_note_list(self):
        """更新便签列表"""
        self.note_listbox.delete(0, tk.END)
        
        # 分离置顶和非置顶便签
        pinned_notes = []
        normal_notes = []
        
        for note in self.notes.values():
            if note['pinned']:
                pinned_notes.append(note)
            else:
                normal_notes.append(note)
        
        # 按修改时间排序
        pinned_notes.sort(key=lambda x: x['modified_time'], reverse=True)
        normal_notes.sort(key=lambda x: x['modified_time'], reverse=True)
        
        # 添加置顶便签
        for note in pinned_notes:
            display_text = f"📌 {note['title']}"
            self.note_listbox.insert(tk.END, display_text)
        
        # 添加普通便签
        for note in normal_notes:
            display_text = f"  {note['title']}"
            self.note_listbox.insert(tk.END, display_text)
            
        # 如果有当前选中的便签,重新选中它
        if self.current_note_id and self.current_note_id in self.notes:
            self.select_note_in_list(self.current_note_id)
    
    def select_note_in_list(self, note_id):
        """在列表中选中指定便签"""
        try:
            for i, note in enumerate(self.notes.values()):
                if note['id'] == note_id:
                    list_index = i
                    # 计算实际索引(考虑置顶便签)
                    pinned_count = sum(1 for n in self.notes.values() if n['pinned'])
                    if not note['pinned']:
                        list_index += pinned_count
                    
                    self.note_listbox.selection_clear(0, tk.END)
                    self.note_listbox.selection_set(list_index)
                    self.note_listbox.see(list_index)
                    break
        except:
            pass
    
    def on_note_select(self, event):
        """便签选择事件"""
        selection = self.note_listbox.curselection()
        if selection:
            index = selection[0]
            
            # 确定实际的note_id
            all_notes = list(self.notes.values())
            pinned_count = sum(1 for note in all_notes if note['pinned'])
            
            if index < pinned_count:
                note = [n for n in all_notes if n['pinned']][index]
            else:
                normal_notes = [n for n in all_notes if not n['pinned']]
                note = normal_notes[index - pinned_count]
            
            self.current_note_id = note['id']
            self.load_note_to_editor(note['id'])
    
    def load_note_to_editor(self, note_id):
        """加载便签到编辑器"""
        if note_id in self.notes:
            note = self.notes[note_id]
            self.title_entry.delete(0, tk.END)
            self.title_entry.insert(0, note['title'])
            
            self.content_text.delete(1.0, tk.END)
            self.content_text.insert(1.0, note['content'])
            
            self.font_size_var.set(str(note['font_size']))
            self.color_var.set(note['color'])
            
            self.apply_note_style()
    
    def apply_note_style(self):
        """应用便签样式"""
        try:
            font_size = int(self.font_size_var.get())
            bg_color = self.colors.get(self.color_var.get(), '#fff380')
            
            self.content_text.configure(
                font=('Arial', font_size),
                bg=bg_color,
                fg='black'
            )
        except ValueError:
            pass
    
    def save_current_note(self):
        """保存当前便签"""
        if not self.current_note_id:
            messagebox.showwarning("警告", "请先创建或选择一个便签!")
            return
        
        title = self.title_entry.get().strip()
        content = self.content_text.get(1.0, tk.END).strip()
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M")
        
        if not title:
            title = "无标题便签"
        
        self.notes[self.current_note_id].update({
            'title': title,
            'content': content,
            'color': self.color_var.get(),
            'font_size': int(self.font_size_var.get()),
            'modified_time': current_time
        })
        
        self.update_note_list()
        self.save_notes()
        self.status_var.set(f"便签已保存 - {current_time}")
        
        # 应用样式
        self.apply_note_style()
    
    def delete_selected_note(self):
        """删除选中的便签"""
        selection = self.note_listbox.curselection()
        if not selection:
            messagebox.showwarning("警告", "请先选择一个便签!")
            return
        
        if messagebox.askyesno("确认删除", "确定要删除选中的便签吗?"):
            index = selection[0]
            
            # 找到对应的note_id
            all_notes = list(self.notes.values())
            pinned_count = sum(1 for note in all_notes if note['pinned'])
            
            if index < pinned_count:
                note = [n for n in all_notes if n['pinned']][index]
            else:
                normal_notes = [n for n in all_notes if not n['pinned']]
                note = normal_notes[index - pinned_count]
            
            del self.notes[note['id']]
            
            if self.current_note_id == note['id']:
                self.current_note_id = None
                self.clear_editor()
            
            self.update_note_list()
            self.save_notes()
            self.status_var.set("便签已删除")
    
    def pin_note(self):
        """置顶/取消置顶便签"""
        if not self.current_note_id:
            messagebox.showwarning("警告", "请先选择或创建一个便签!")
            return
        
        is_pinned = self.notes[self.current_note_id]['pinned']
        self.notes[self.current_note_id]['pinned'] = not is_pinned
        action = "取消置顶" if is_pinned else "已置顶"
        
        self.update_note_list()
        self.save_notes()
        self.status_var.set(f"便签{action}")
    
    def clear_editor(self):
        """清空编辑器"""
        self.title_entry.delete(0, tk.END)
        self.content_text.delete(1.0, tk.END)
        self.current_note_id = None
        self.status_var.set("编辑器已清空")
    
    def save_notes(self):
        """保存便签到文件"""
        try:
            with open(self.data_file, 'w', encoding='utf-8') as f:
                json.dump(self.notes, f, ensure_ascii=False, indent=2)
        except Exception as e:
            messagebox.showerror("错误", f"保存便签失败:{str(e)}")
    
    def load_notes(self):
        """从文件加载便签"""
        try:
            if os.path.exists(self.data_file):
                with open(self.data_file, 'r', encoding='utf-8') as f:
                    self.notes = json.load(f)
                
                # 兼容旧数据
                for note in self.notes.values():
                    if 'pinned' not in note:
                        note['pinned'] = False
                    if 'font_size' not in note:
                        note['font_size'] = 12
                
                self.update_note_list()
                self.status_var.set(f"已加载 {len(self.notes)} 个便签")
            else:
                self.notes = {}
                self.status_var.set("欢迎使用桌面便签工具")
        except Exception as e:
            messagebox.showerror("错误", f"加载便签失败:{str(e)}")
            self.notes = {}

def main():
    root = tk.Tk()
    app = StickyNote(root)
    
    # 设置窗口图标(需要ico文件)
    try:
        root.iconbitmap('sticky_note.ico')
    except:
        pass
    
    # 居中显示窗口
    root.update_idletasks()
    x = (root.winfo_screenwidth() // 2) - (root.winfo_width() // 2)
    y = (root.winfo_screenheight() // 2) - (root.winfo_height() // 2)
    root.geometry(f"+{x}+{y}")
    
    root.mainloop()

if __name__ == "__main__":
    main()

这个桌面便签工具还需要一个配置文件 requirements.txt

# 这个程序只使用了Python标准库,无需额外依赖
# 但如果您需要打包成exe,可以安装pyinstaller:
# pip install pyinstaller

功能特点:

🎯 ​核心功能

  • ✅ ​创建/编辑/删除便签​ – 完整的CRUD操作
  • ✅ ​便签列表管理​ – 清晰展示所有便签,支持置顶显示
  • ✅ ​富文本编辑​ – 可调节字体大小和背景颜色
  • ✅ ​数据持久化​ – 自动保存到JSON文件
  • ✅ ​置顶功能​ – 重要便签可以置顶显示

🎨 ​界面特色

  • 🖼️ ​现代化UI设计​ – 仿Windows 10风格
  • 🌈 ​多彩主题​ – 6种预设便签颜色
  • 📱 ​响应式布局​ – 自适应窗口大小
  • 🔄 ​实时状态反馈​ – 底部状态栏显示操作信息

💾 ​数据管理

  • 📁 ​自动保存​ – 编辑内容实时保存
  • 🔄 ​数据恢复​ – 程序重启后自动加载历史便签
  • 🛡️ ​错误处理​ – 完善的异常处理机制

使用方法:

  1. 运行程序​: python sticky_notes.py
  2. 基本操作​:
    • 点击”新建便签”创建便签
    • 在左侧列表中选择便签进行编辑
    • 修改标题和内容后点击”保存便签”
    • 使用颜色和字体大小下拉框自定义样式
    • 点击”置顶显示”将重要便签固定在顶部
  3. 高级功能​:
    • 便签会自动保存到同目录下的 sticky_notes.json 文件
    • 支持便签置顶,重要事项不会丢失
    • 所有操作都有状态提示

扩展建议:

如果需要更多功能,可以考虑添加:

  • 🔍 便签搜索功能
  • 🏷️ 便签分类标签
  • ⏰ 提醒功能
  • 🖼️ 插入图片功能
  • 🌐 云同步功能
  • 📦 打包成exe文件便于分发

这个便签工具具有完整的功能和良好的用户体验,可以直接在Windows 10上使用!

© 版权声明
THE END
喜欢就点个赞,支持一下吧!
点赞20 分享
评论 抢沙发
头像
欢迎您留下评论!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容