python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python便签

基于Python开发一个桌面便签工具

作者:小庄-Python办公

这篇文章主要为大家详细介绍了如何基于Python开发一个桌面便签工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

前言

一个功能丰富的桌面置顶便签小工具,使用Python和tkinter开发。

功能特点

使用方法

方法:直接运行Python文件

python sticky_notes.py

快捷键

Ctrl + S: 保存文件

Ctrl + N: 新建便签

Ctrl + O: 打开文件

菜单功能

文件菜单

设置菜单

帮助菜单

关于: 查看程序信息和使用说明

工具栏按钮

新建: 创建新便签

保存: 保存当前内容

清空: 清空所有文本内容

自动保存功能

程序会自动保存以下内容:

系统要求

Python 3.6 或更高版本

tkinter 库(Python标准库,通常已包含)

文件说明

注意事项

故障排除

如果程序无法启动,请检查:

完整代码

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便签内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文