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

 更新时间:2026年02月03日 09:26:26   作者:Yorlen_Zhang  
Tkinter库提供了丰富的控件和布局管理器,使得开发者可以轻松构建具有窗口、按钮、文本框等元素的应用程序,下面我们就来看看Python如何结合Tkinter编写一个win10桌面便签工具吧

Python的GUI(图形用户界面)库Tkinter是Python标准库的一部分,用于创建桌面应用程序。"Python GUI Win10 便贴"项目就是利用Tkinter来模仿Windows 10操作系统中的便签功能,提供了类似的功能,让用户可以在桌面上创建、编辑和管理文本小记。

Tkinter库提供了丰富的控件和布局管理器,使得开发者可以轻松构建具有窗口、按钮、文本框等元素的应用程序。在"Python tkinter GUI Windows10 sticky note"这个项目中,开发者可能使用了Tkinter的`Tk`类来创建主窗口,`Label`控件来显示文本,`Text`控件来实现可编辑的便签内容,并可能使用了`Button`控件来添加、保存或删除便签。

在设计这样一个GUI应用时,开发者可能考虑了以下几点:

1. 用户交互:通过点击按钮或者使用快捷键来实现新建、编辑、保存、删除等功能。

2. 数据持久化:为了保存用户的便签内容,开发者可能使用了文件存储(如JSON或pickle格式)或数据库来存储数据,确保即使程序关闭后,便签内容也不会丢失。

3. 界面设计:模仿Windows 10的风格,包括颜色、字体、图标等,以提供一致的用户体验。

4. 窗口管理:利用Tkinter的`geometry`方法调整窗口大小和位置,允许用户自由拖动和调整大小。

5. 事件绑定:使用`bind`函数监听键盘和鼠标事件,响应用户的操作。

6. 多个便签管理:如果程序支持创建多个便签,可能使用列表或其他容器结构来存储每个便签对象。

在实际使用中,用户可以通过这个Python实现的"Win10 便贴"轻松记录日常琐事、待办事项或者灵感,享受与Windows 10系统一致的便利体验,同时得益于Python和Tkinter的易用性,开发者可以快速实现和定制自己的需求。

以下是完整代码

可以拿去自己生成小程序

import tkinter as tk
from tkinter import colorchooser, font, messagebox, simpledialog
import json
import os
from pathlib import Path
from datetime import datetime

# 常量定义(便于维护)
DEFAULT_PASSWORD = "123456"
MIN_WIDTH = 200
MIN_HEIGHT = 150
AUTO_SAVE_INTERVAL = 5000  # 5秒自动保存
PURE_MODE_DELAY = 10000  # 10秒进入纯净模式
CONFIG_FILE = Path.home() / "sticky_note_config.json"  # 保存到用户目录
CONTENT_FILE = Path.home() / "sticky_note_content.txt"
PASSWORD_FILE = Path.home() / "sticky_note_pwd.json"


class BorderlessStickyNote:
    def __init__(self, root):
        self.root = root
        self.root.title("极简便签")
        self.root.geometry("400x500+100+100")

        # 核心状态变量
        self.root.overrideredirect(True)  # 移除窗口装饰
        self.resizing = False
        self.moving = False
        self._drag_data = {"x": 0, "y": 0}
        self.hide_timer = None

        # 样式配置
        self.current_font_family = "Microsoft YaHei"
        self.current_font_size = 14
        self.current_font_color = "#2C3E50"
        self.current_bg_color = "#FFFEF0"
        self.current_alpha = 0.95
        self.is_topmost = True

        # 密码配置
        self.close_password = self.load_password()

        # 初始化UI
        self.root.attributes('-topmost', self.is_topmost)
        self.root.attributes('-alpha', self.current_alpha)
        self.load_config()  # 加载配置(覆盖默认值)
        self.create_ui()
        self.create_context_menu()
        self.bind_events()
        self.load_content()

        # 启动定时任务
        self.schedule_pure_mode()
        self.schedule_auto_save()

    def create_ui(self):
        """创建界面(优化布局和初始提示)"""
        # 主容器(调整大小边框)
        self.main_container = tk.Frame(self.root, bg="#CCCCCC", cursor="arrow")
        self.main_container.pack(fill=tk.BOTH, expand=True)

        # 内容区域
        self.main_frame = tk.Frame(self.main_container, bg=self.current_bg_color, bd=0)
        self.main_frame.pack(fill=tk.BOTH, expand=True, padx=1, pady=1)

        # 文本编辑区(增加初始提示)
        self.text_area = tk.Text(
            self.main_frame,
            wrap=tk.WORD,
            font=(self.current_font_family, self.current_font_size),
            fg=self.current_font_color,
            bg=self.current_bg_color,
            padx=20,
            pady=20,
            undo=True,
            maxundo=50,  # 增加撤销次数
            relief=tk.FLAT,
            highlightthickness=0,
            insertbackground=self.current_font_color,
            selectbackground="#3498DB",
            selectforeground="white",
            spacing1=3,
            spacing3=3,
            borderwidth=0
        )
        self.text_area.pack(fill=tk.BOTH, expand=True, padx=2, pady=2)

        # 初始提示文字
        if not os.path.exists(CONTENT_FILE) or os.path.getsize(CONTENT_FILE) == 0:
            self.text_area.insert("1.0",
                                  "✨ 欢迎使用极简便签\n\n- 右键可打开功能菜单\n- Alt+左键拖动移动窗口\n- 边缘/角落拖动调整大小\n- Ctrl+滚轮调整字号")
            self.text_area.tag_add("hint", "1.0", "5.0")
            self.text_area.tag_config("hint", foreground="#999999")

    def create_context_menu(self):
        """创建优化后的右键菜单(修复勾选状态、新增功能)"""
        # 置顶状态变量(持久化)
        self.topmost_var = tk.BooleanVar(value=self.is_topmost)

        self.menu = tk.Menu(self.root, tearoff=0, bg="white", fg="#333",
                            activebackground="#E0E0E0", font=("Microsoft YaHei", 10))

        # 窗口控制(优化)
        self.menu.add_command(label="🖱️ 移动窗口", command=self.start_move_mode)
        self.menu.add_command(label="🗕 最小化窗口", command=self.minimize_window)
        self.menu.add_checkbutton(
            label="📌 窗口置顶",
            variable=self.topmost_var,
            command=self.toggle_topmost
        )
        self.menu.add_separator()

        # 字体设置(新增字体家族选择)
        font_menu = tk.Menu(self.menu, tearoff=0, bg="white")
        # 字体家族子菜单
        family_menu = tk.Menu(font_menu, tearoff=0, bg="white")
        common_fonts = ["Microsoft YaHei", "SimSun", "SimHei", "KaiTi", "Arial", "Times New Roman"]
        for f in common_fonts:
            family_menu.add_command(
                label=f"  {f} {'✓' if f == self.current_font_family else ''}",
                command=lambda fm=f: self.set_font_family(fm)
            )
        font_menu.add_cascade(label="字体家族", menu=family_menu)

        # 字体大小子菜单
        size_menu = tk.Menu(font_menu, tearoff=0, bg="white")
        for size in [10, 12, 14, 16, 18, 20, 24, 28, 32]:
            size_menu.add_command(
                label=f"  {size}px {'✓' if size == self.current_font_size else ''}",
                command=lambda s=size: self.set_font_size(s)
            )
        font_menu.add_cascade(label="字体大小", menu=size_menu)
        self.menu.add_cascade(label="✏️ 字体设置", menu=font_menu)

        # 样式设置
        self.menu.add_command(label="🎨 文字颜色", command=self.choose_color)
        self.menu.add_command(label="🖌️ 背景颜色", command=self.choose_bg_color)

        # 透明度(优化显示)
        alpha_menu = tk.Menu(self.menu, tearoff=0, bg="white")
        alpha_levels = [
            (0.3, "30% 透视"),
            (0.5, "50% 半透明"),
            (0.7, "70% 轻薄"),
            (0.85, "85% 淡雅"),
            (0.95, "95% 默认"),
            (1.0, "100% 不透明")
        ]
        for alpha_val, label_text in alpha_levels:
            alpha_menu.add_command(
                label=f"  {label_text} {'✓' if abs(alpha_val - self.current_alpha) < 0.01 else ''}",
                command=lambda a=alpha_val: self.set_alpha(a)
            )
        self.menu.add_cascade(label="🌫️ 背景透明度", menu=alpha_menu)
        self.menu.add_separator()

        # 编辑功能(绑定快捷键)
        self.menu.add_command(label="𝗕 加粗 (Ctrl+B)", command=self.toggle_bold)
        self.menu.add_command(label="↩️ 撤销 (Ctrl+Z)", command=lambda: self.text_area.edit_undo())
        self.menu.add_command(label="↪️ 重做 (Ctrl+Y)", command=lambda: self.text_area.edit_redo())
        self.menu.add_separator()
        self.menu.add_command(label="全选 (Ctrl+A)", command=self.select_all)
        self.menu.add_command(label="复制 (Ctrl+C)", command=self.copy_text)
        self.menu.add_command(label="粘贴 (Ctrl+V)", command=self.paste_text)
        self.menu.add_separator()

        # 高级功能
        self.menu.add_command(label="🔄 清空内容", command=self.clear_text, foreground="#E74C3C")
        self.menu.add_command(label="🔐 修改关闭密码", command=self.change_password)
        self.menu.add_command(label="ℹ️ 关于", command=self.show_about)
        self.menu.add_separator()

        # 退出(优化提示)
        self.menu.add_command(label="🚪 退出程序 (Alt+F4/Ctrl+Q)", command=self.on_closing,
                              foreground="#C0392B")

    # -------------------------- 核心功能:修复调整大小 --------------------------
    def check_resize_cursor(self, event):
        """优化:扩大边缘检测区域(20px),覆盖所有边缘,光标样式更精准"""
        width = self.main_container.winfo_width()
        height = self.main_container.winfo_height()
        x, y = event.x, event.y
        edge_size = 20  # 扩大检测区域,提升易用性

        # 检测各边缘
        is_left = x < edge_size
        is_right = width - x < edge_size
        is_top = y < edge_size
        is_bottom = height - y < edge_size

        # 按优先级设置光标
        if is_left and is_top:
            self.main_container.config(cursor="size_nw_se")
        elif is_left and is_bottom:
            self.main_container.config(cursor="size_ne_sw")
        elif is_right and is_top:
            self.main_container.config(cursor="size_ne_sw")
        elif is_right and is_bottom:
            self.main_container.config(cursor="size_nw_se")
        elif is_left or is_right:
            self.main_container.config(cursor="sb_h_double_arrow")
        elif is_top or is_bottom:
            self.main_container.config(cursor="sb_v_double_arrow")
        else:
            self.main_container.config(cursor="arrow")

    def start_resize(self, event):
        """修复:记录完整初始状态,明确边缘类型,避免计算偏差"""
        width = self.main_container.winfo_width()
        height = self.main_container.winfo_height()
        x, y = event.x, event.y
        edge_size = 20

        # 仅在边缘区域启动调整
        if not (x < edge_size or width - x < edge_size or y < edge_size or height - y < edge_size):
            return

        self.resizing = True
        self._resize_start = {
            "start_x": event.x_root,  # 记录鼠标绝对位置,避免容器偏移影响
            "start_y": event.y_root,
            "init_width": self.root.winfo_width(),
            "init_height": self.root.winfo_height(),
            "init_x": self.root.winfo_x(),  # 记录窗口初始位置,支持左上边缘调整
            "init_y": self.root.winfo_y(),
            "edge": self._get_resize_edge(x, y, width, height, edge_size)
        }

    def _get_resize_edge(self, x, y, width, height, edge_size):
        """辅助函数:判断调整的边缘类型"""
        is_left = x < edge_size
        is_right = width - x < edge_size
        is_top = y < edge_size
        is_bottom = height - y < edge_size

        if is_left and is_top:
            return "top_left"
        elif is_left and is_bottom:
            return "bottom_left"
        elif is_right and is_top:
            return "top_right"
        elif is_right and is_bottom:
            return "bottom_right"
        elif is_left:
            return "left"
        elif is_right:
            return "right"
        elif is_top:
            return "top"
        elif is_bottom:
            return "bottom"
        return None

    def do_resize(self, event):
        """修复:基于初始状态计算尺寸,支持所有边缘调整,限制最小尺寸"""
        if not self.resizing or not hasattr(self, "_resize_start"):
            return

        start = self._resize_start
        delta_x = event.x_root - start["start_x"]
        delta_y = event.y_root - start["start_y"]
        min_w, min_h = MIN_WIDTH, MIN_HEIGHT  # 最小尺寸

        # 根据边缘类型计算新尺寸和位置
        if start["edge"] == "right":
            new_w = max(min_w, start["init_width"] + delta_x)
            self.root.geometry(f"{int(new_w)}x{self.root.winfo_height()}")
        elif start["edge"] == "bottom":
            new_h = max(min_h, start["init_height"] + delta_y)
            self.root.geometry(f"{self.root.winfo_width()}x{int(new_h)}")
        elif start["edge"] == "bottom_right":
            new_w = max(min_w, start["init_width"] + delta_x)
            new_h = max(min_h, start["init_height"] + delta_y)
            self.root.geometry(f"{int(new_w)}x{int(new_h)}")
        elif start["edge"] == "left":
            new_w = max(min_w, start["init_width"] - delta_x)
            new_x = start["init_x"] + delta_x
            self.root.geometry(f"{int(new_w)}x{self.root.winfo_height()}+{int(new_x)}+{self.root.winfo_y()}")
        elif start["edge"] == "top":
            new_h = max(min_h, start["init_height"] - delta_y)
            new_y = start["init_y"] + delta_y
            self.root.geometry(f"{self.root.winfo_width()}x{int(new_h)}+{self.root.winfo_x()}+{int(new_y)}")
        elif start["edge"] == "top_left":
            new_w = max(min_w, start["init_width"] - delta_x)
            new_h = max(min_h, start["init_height"] - delta_y)
            new_x = start["init_x"] + delta_x
            new_y = start["init_y"] + delta_y
            self.root.geometry(f"{int(new_w)}x{int(new_h)}+{int(new_x)}+{int(new_y)}")
        elif start["edge"] == "top_right":
            new_w = max(min_w, start["init_width"] + delta_x)
            new_h = max(min_h, start["init_height"] - delta_y)
            new_y = start["init_y"] + delta_y
            self.root.geometry(f"{int(new_w)}x{int(new_h)}+{self.root.winfo_x()}+{int(new_y)}")
        elif start["edge"] == "bottom_left":
            new_w = max(min_w, start["init_width"] - delta_x)
            new_h = max(min_h, start["init_height"] + delta_y)
            new_x = start["init_x"] + delta_x
            self.root.geometry(f"{int(new_w)}x{int(new_h)}+{int(new_x)}+{self.root.winfo_y()}")

    def _stop_resize(self, event):
        """新增:鼠标释放时重置调整状态,保存窗口配置"""
        if self.resizing:
            self.resizing = False
            self.save_config()  # 调整后保存尺寸和位置

    # -------------------------- 移动窗口功能 --------------------------
    def start_move_mode(self):
        """修复移动窗口逻辑:基于鼠标指针位置计算"""
        self.moving = True
        self.root.config(cursor="fleur")
        # 记录初始偏移量
        self._drag_data["x"] = self.root.winfo_pointerx() - self.root.winfo_x()
        self._drag_data["y"] = self.root.winfo_pointery() - self.root.winfo_y()
        # 绑定移动和停止事件
        self.root.bind('<Motion>', self.do_move)
        self.root.bind('<ButtonRelease-1>', self.stop_move_mode)

    def do_move(self, event):
        """正确的窗口移动逻辑"""
        if self.moving:
            x = self.root.winfo_pointerx() - self._drag_data["x"]
            y = self.root.winfo_pointery() - self._drag_data["y"]
            self.root.geometry(f"+{x}+{y}")

    def stop_move_mode(self, event):
        """停止移动模式(优化恢复逻辑)"""
        self.moving = False
        self.root.config(cursor="arrow")
        self.root.unbind('<Motion>')
        self.root.unbind('<ButtonRelease-1>')
        self.save_config()  # 移动后保存位置

    def start_alt_move(self, event):
        self._drag_data = {"x": event.x, "y": event.y, "moving": True}

    def do_alt_move(self, event):
        if hasattr(self, '_drag_data') and self._drag_data.get("moving"):
            x = self.root.winfo_x() + (event.x - self._drag_data["x"])
            y = self.root.winfo_y() + (event.y - self._drag_data["y"])
            self.root.geometry(f"+{x}+{y}")

    def stop_alt_move(self, event):
        if hasattr(self, '_drag_data'):
            self._drag_data["moving"] = False

    # -------------------------- 新增功能 --------------------------
    def minimize_window(self):
        """最小化窗口(无边框窗口专用)"""
        self.root.overrideredirect(False)  # 临时恢复窗口装饰
        self.root.iconify()  # 最小化
        # 恢复无边框(最小化还原后)
        self.root.bind('<Map>', lambda e: self.root.overrideredirect(True) if e.widget == self.root else None)

    def set_font_family(self, family):
        """新增:设置字体家族"""
        self.current_font_family = family
        self.update_font()
        self.save_config()
        self.create_context_menu()  # 更新菜单勾选状态

    def change_password(self):
        """新增:修改关闭密码"""
        old_pwd = simpledialog.askstring("验证旧密码", "请输入当前关闭密码:", show="*", parent=self.root)
        if old_pwd != self.close_password:
            messagebox.showerror("错误", "旧密码不正确!", parent=self.root)
            return

        new_pwd = simpledialog.askstring("设置新密码", "请输入新的关闭密码(至少4位):", show="*", parent=self.root)
        if not new_pwd or len(new_pwd) < 4:
            messagebox.warning("提示", "密码长度不能少于4位!", parent=self.root)
            return

        confirm_pwd = simpledialog.askstring("确认新密码", "请再次输入新密码:", show="*", parent=self.root)
        if new_pwd == confirm_pwd:
            self.close_password = new_pwd
            self.save_password()
            messagebox.showinfo("成功", "密码修改成功!", parent=self.root)
        else:
            messagebox.showerror("错误", "两次输入的密码不一致!", parent=self.root)

    def load_password(self):
        """加载自定义密码"""
        try:
            if os.path.exists(PASSWORD_FILE):
                with open(PASSWORD_FILE, 'r', encoding='utf-8') as f:
                    return json.load(f).get("password", DEFAULT_PASSWORD)
            return DEFAULT_PASSWORD
        except:
            return DEFAULT_PASSWORD

    def save_password(self):
        """保存密码到文件"""
        try:
            with open(PASSWORD_FILE, 'w', encoding='utf-8') as f:
                json.dump({"password": self.close_password}, f)
        except Exception as e:
            messagebox.showerror("错误", f"保存密码失败:{str(e)}", parent=self.root)

    def show_about(self):
        """新增:关于窗口"""
        about_window = tk.Toplevel(self.root)
        about_window.title("关于极简便签")
        about_window.geometry("300x200+%d+%d" % (self.root.winfo_x() + 50, self.root.winfo_y() + 50))
        about_window.resizable(False, False)
        about_window.attributes('-topmost', True)

        tk.Label(about_window, text="极简便签 v1.0", font=("Microsoft YaHei", 16)).pack(pady=20)
        tk.Label(about_window, text="基于Python Tkinter开发").pack()
        tk.Label(about_window, text="✨ 轻量 · 简洁 · 易用").pack(pady=5)
        tk.Button(about_window, text="确定", command=about_window.destroy, width=10).pack(pady=20)

    # -------------------------- 原有功能优化 --------------------------
    def toggle_topmost(self):
        """优化:保存置顶状态到配置"""
        self.is_topmost = self.topmost_var.get()
        self.root.attributes('-topmost', self.is_topmost)
        self.save_config()

    def enter_pure_mode(self):
        """优化纯净模式:鼠标移动也退出"""
        self.main_container.config(bg=self.current_bg_color)
        self.text_area.config(padx=25, pady=25)
        # 鼠标移动时退出纯净模式
        self.root.bind('<Motion>', self.exit_pure_mode_on_move)

    def exit_pure_mode_on_move(self, event):
        """鼠标移动退出纯净模式"""
        self.exit_pure_mode()
        self.root.unbind('<Motion>')

    def exit_pure_mode(self):
        """优化退出纯净模式逻辑"""
        self.main_container.config(bg="#CCCCCC")
        self.text_area.config(padx=20, pady=20)
        self.schedule_pure_mode()

    def schedule_pure_mode(self):
        if self.hide_timer:
            self.root.after_cancel(self.hide_timer)
        self.hide_timer = self.root.after(PURE_MODE_DELAY, self.enter_pure_mode)

    def schedule_auto_save(self):
        """优化自动保存:添加成功提示(可选)"""
        try:
            self.save_content()
            self.save_config()
        except Exception as e:
            messagebox.warning("提示", f"自动保存失败:{str(e)}", parent=self.root)
        finally:
            self.root.after(AUTO_SAVE_INTERVAL, self.schedule_auto_save)

    def set_font_size(self, size):
        self.current_font_size = size
        self.update_font()
        self.save_config()
        self.create_context_menu()

    def update_font(self):
        new_font = font.Font(family=self.current_font_family, size=self.current_font_size)
        self.text_area.config(
            font=new_font,
            fg=self.current_font_color,
            insertbackground=self.current_font_color
        )

    def choose_color(self):
        color = colorchooser.askcolor(color=self.current_font_color, title="选择文字颜色")
        if color[1]:
            self.current_font_color = color[1]
            self.update_font()
            self.save_config()

    def choose_bg_color(self):
        color = colorchooser.askcolor(color=self.current_bg_color, title="选择背景颜色")
        if color[1]:
            self.current_bg_color = color[1]
            self.main_frame.config(bg=self.current_bg_color)
            self.text_area.config(bg=self.current_bg_color)
            self.save_config()

    def toggle_bold(self):
        try:
            if self.text_area.tag_ranges("sel"):
                current_tags = self.text_area.tag_names("sel.first")
                if "bold" in current_tags:
                    self.text_area.tag_remove("bold", "sel.first", "sel.last")
                else:
                    bold_font = font.Font(self.text_area, self.text_area.cget("font"))
                    bold_font.configure(weight="bold")
                    self.text_area.tag_configure("bold", font=bold_font)
                    self.text_area.tag_add("bold", "sel.first", "sel.last")
        except tk.TclError:
            pass

    def show_menu(self, event):
        if not self.resizing:
            self.menu.post(event.x_root, event.y_root)
        self.resizing = False

    def set_alpha(self, alpha_val):
        self.current_alpha = alpha_val
        self.root.attributes('-alpha', alpha_val)
        self.save_config()
        self.create_context_menu()

    def on_closing(self):
        """优化关闭逻辑:更友好的提示"""
        if not messagebox.askyesno("确认退出", "确定要退出极简便签吗?\n(内容会自动保存)", parent=self.root):
            return

        password = simpledialog.askstring(
            "安全验证",
            "请输入关闭密码:",
            parent=self.root,
            show="*"
        )

        if password is None:
            return
        elif password == self.close_password:
            self.save_content()
            self.save_config()
            self.root.destroy()
        else:
            messagebox.showerror("密码错误", f"密码不正确!\n\n当前默认密码:{DEFAULT_PASSWORD}(若未修改)",
                                 parent=self.root)

    def bind_events(self):
        """修复:补充鼠标释放事件,重置调整状态,避免冲突"""
        # 基础交互
        self.text_area.bind('<Alt-Button-1>', self.start_alt_move)
        self.text_area.bind('<Alt-B1-Motion>', self.do_alt_move)
        self.text_area.bind('<Alt-ButtonRelease-1>', self.stop_alt_move)
        self.text_area.bind("<Button-3>", self.show_menu)
        self.text_area.bind("<Button-1>", self.on_text_click)
        self.text_area.bind("<Key>", self.on_text_input)
        self.text_area.bind("<Control-MouseWheel>", self.on_mouse_wheel)

        # 快捷键绑定
        self.root.bind('<Control-b>', lambda e: self.toggle_bold())
        self.root.bind('<Control-a>', lambda e: self.select_all())
        self.root.bind('<Control-c>', lambda e: self.copy_text())
        self.root.bind('<Control-v>', lambda e: self.paste_text())
        self.root.bind('<Control-z>', lambda e: self.text_area.edit_undo())
        self.root.bind('<Control-y>', lambda e: self.text_area.edit_redo())
        self.root.bind('<Control-q>', lambda e: self.on_closing())
        self.root.bind('<Alt-F4>', lambda e: self.on_closing())

        # 调整大小(核心修复)
        self.main_container.bind('<Motion>', self.check_resize_cursor)
        self.main_container.bind('<Button-1>', self.start_resize)
        self.main_container.bind('<B1-Motion>', self.do_resize)
        self.main_container.bind('<ButtonRelease-1>', self._stop_resize)

    def on_text_input(self, event):
        """输入文字时移除初始提示"""
        if self.text_area.tag_ranges("hint"):
            self.text_area.delete("hint.first", "hint.last")
            self.text_area.tag_remove("hint", "1.0", tk.END)
        self.schedule_pure_mode()

    def copy_text(self):
        self.text_area.event_generate("<<Copy>>")

    def paste_text(self):
        self.text_area.event_generate("<<Paste>>")

    def select_all(self):
        self.text_area.tag_add("sel", "1.0", tk.END)

    def clear_text(self):
        if messagebox.askyesno("确认清空", "确定要清空所有内容吗?\n此操作不可撤销!", parent=self.root):
            self.text_area.delete("1.0", tk.END)
            self.save_content()

    def save_content(self):
        try:
            with open(CONTENT_FILE, 'w', encoding='utf-8') as f:
                content = self.text_area.get("1.0", tk.END)
                f.write(content)
        except Exception as e:
            messagebox.showerror("错误", f"保存内容失败:{str(e)}", parent=self.root)

    def load_content(self):
        if os.path.exists(CONTENT_FILE):
            try:
                with open(CONTENT_FILE, 'r', encoding='utf-8') as f:
                    content = f.read()
                    self.text_area.delete("1.0", tk.END)
                    self.text_area.insert("1.0", content)
            except Exception as e:
                messagebox.showerror("错误", f"加载内容失败:{str(e)}", parent=self.root)

    def save_config(self):
        config = {
            'font_family': self.current_font_family,
            'font_size': self.current_font_size,
            'font_color': self.current_font_color,
            'bg_color': self.current_bg_color,
            'alpha': self.current_alpha,
            'geometry': self.root.geometry(),
            'is_topmost': self.is_topmost
        }
        try:
            with open(CONFIG_FILE, 'w', encoding='utf-8') as f:
                json.dump(config, f, ensure_ascii=False, indent=2)
        except Exception as e:
            messagebox.showerror("错误", f"保存配置失败:{str(e)}", parent=self.root)

    def load_config(self):
        if os.path.exists(CONFIG_FILE):
            try:
                with open(CONFIG_FILE, 'r', encoding='utf-8') as f:
                    config = json.load(f)
                    self.current_font_family = config.get('font_family', self.current_font_family)
                    self.current_font_size = config.get('font_size', self.current_font_size)
                    self.current_font_color = config.get('font_color', self.current_font_color)
                    self.current_bg_color = config.get('bg_color', self.current_bg_color)
                    self.current_alpha = config.get('alpha', self.current_alpha)
                    self.is_topmost = config.get('is_topmost', self.is_topmost)

                    if 'geometry' in config:
                        self.root.geometry(config['geometry'])
            except Exception as e:
                messagebox.warning("提示", f"加载配置失败,使用默认设置:{str(e)}", parent=self.root)

    def on_text_click(self, event=None):
        current_padding = int(self.text_area.cget("padx"))
        if current_padding > 20:
            self.exit_pure_mode()
        else:
            self.schedule_pure_mode()

    def on_mouse_wheel(self, event):
        if event.delta > 0:
            new_size = min(self.current_font_size + 1, 72)
        else:
            new_size = max(self.current_font_size - 1, 8)

        if new_size != self.current_font_size:
            self.current_font_size = new_size
            self.update_font()
            self.save_config()
            self.create_context_menu()


if __name__ == "__main__":
    root = tk.Tk()
    app = BorderlessStickyNote(root)
    root.mainloop()

以上就是基于Python编写一个win10桌面便签工具的详细内容,更多关于Python桌面便签工具的资料请关注脚本之家其它相关文章!

相关文章

  • Python中os.path模块的8个神奇函数分享

    Python中os.path模块的8个神奇函数分享

    在Python编程中,os.path模块是一个非常重要的模块,它提供了用于处理文件路径和目录的函数,本文将介绍os.path模块中最常用的8个内置函数,需要的可以参考下
    2023-11-11
  • PyQt5 如何让界面和逻辑分离的方法

    PyQt5 如何让界面和逻辑分离的方法

    这篇文章主要介绍了PyQt5 如何让界面和逻辑分离的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • 深入探讨Pandas数据清洗与高效分析

    深入探讨Pandas数据清洗与高效分析

    这篇文章主要介绍了深入探讨Pandas数据清洗与高效分析,Pandas 是 Python 中最强大的数据处理库之一,广泛应用于数据分析、统计建模和科学计算领域,本文将深入探讨 Pandas 的高阶用法,包括数据清洗、高效的数据操作以及与机器学习结合的应用
    2021-10-10
  • Python编程scoketServer实现多线程同步实例代码

    Python编程scoketServer实现多线程同步实例代码

    这篇文章主要介绍了Python编程scoketServer实现多线程同步实例代码,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • python自动化办公操作excel的示例详解

    python自动化办公操作excel的示例详解

    这篇文章主要为大家详细介绍了如何利用python来实现自动化办公操作excel文件进行各种样式展示,并自动发送文件给"老板"的邮箱,希望对大家有所帮助
    2024-03-03
  • Python多重继承的方法解析执行顺序实例分析

    Python多重继承的方法解析执行顺序实例分析

    这篇文章主要介绍了Python多重继承的方法解析执行顺序,结合实例形式分析了Python多重继承时存在方法命名冲突情况的解析执行顺序与相关原理,需要的朋友可以参考下
    2018-05-05
  • python 判断文件还是文件夹的简单实例

    python 判断文件还是文件夹的简单实例

    今天小编就为大家分享一篇python 判断文件还是文件夹的简单实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-06-06
  • 详解Python使用OpenCV如何确定一个对象的方向

    详解Python使用OpenCV如何确定一个对象的方向

    在本教程中,我们将构建一个程序,该程序可以使用流行的计算机视觉库 OpenCV 确定对象的方向(即以度为单位的旋转角度),感兴趣的小伙伴可以了解一下
    2022-10-10
  • Python调用实现最小二乘法的方法详解

    Python调用实现最小二乘法的方法详解

    所谓线性最小二乘法,可以理解为是解方程的延续,区别在于,当未知量远小于方程数的时候,将得到一个无解的问题。本文主要和大家分享Python调用实现最小二乘法的方法,需要的可以参考一下
    2023-04-04
  • Python爬虫之Selenium实现键盘事件

    Python爬虫之Selenium实现键盘事件

    这篇文章主要介绍了Python爬虫之Selenium实现键盘事件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-12-12

最新评论