用 Python 30 分钟做出自己的记事本

那天下午,我对着电脑屏幕发呆

事情是这样的。

上周三下午,我正写着代码,突然需要记点东西。打开系统自带的记事本,白底黑字,功能倒是够用,但总觉得哪里不对劲。我想要个深色背景保护眼睛,想把常用短语存成快捷按钮,想随手记录的时候自动加上时间戳。

打开软件商店搜了一圈,免费的要么带广告,要么功能臃肿得像个航母。付费的倒是有几个不错的,可为了这点小需求花几十块钱,总觉得不太划算。

我看了眼时间,下午三点。离下班还有两个小时。

一个念头冒了出来:干脆自己写一个。

为什么自己写?因为真的不难

很多人听到"自己做软件"就觉得是件大事,要学一堆框架,要懂什么设计模式,要会各种高深的技术。

真不是。

Python 写桌面程序,比你想的简单得多。标准库里的 tkinter 就能搞定界面,几句话就能搭出一个能用的窗口。加上 tkinterdnd2 就能支持拖拽文件,再加上几行代码就能实现自动保存。

我花了大概半小时,真的只用了半小时,就做出了一个满足日常需求的记事本。

整个过程没有复杂的架构设计,没有晦涩的框架配置,就是写代码,跑起来,用着爽。

今天我就把这个过程完整写出来。你跟着做一遍,会发现"自己做软件"这件事,门槛比你想象的低得多。

第一步:搭个能用的窗口

打开你的编辑器,新建一个 Python 文件,就叫 my_notepad.py。先把最基本的窗口搭出来。

python 复制代码
import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox

class MyNotepad:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("我的记事本")
        self.root.geometry("800x600")
        
        # 创建文本框
        self.text_area = scrolledtext.ScrolledText(
            self.root, 
            wrap=tk.WORD, 
            font=("微软雅黑", 12)
        )
        self.text_area.pack(fill=tk.BOTH, expand=True)
        
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = MyNotepad()
    app.run()

运行一下,一个窗口就出来了。中间是可以打字的大框框,字体看着舒服,窗口大小刚好。

这几行代码干了几件事:创建了一个窗口,加了一个带滚动条的文本框,设置好了字体。就这么简单。

第二步:加上菜单栏

空窗口不好看,也不实用。把文件菜单加上,能新建、打开、保存文件。

ini 复制代码
def __init__(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_file)
    file_menu.add_command(label="打开", command=self.open_file)
    file_menu.add_command(label="保存", command=self.save_file)
    file_menu.add_separator()
    file_menu.add_command(label="退出", command=self.root.quit)

def new_file(self):
    self.text_area.delete(1.0, tk.END)
    self.root.title("我的记事本 - 新建文件")

def open_file(self):
    file_path = filedialog.askopenfilename(
        defaultextension=".txt",
        filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
    )
    if file_path:
        with open(file_path, "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.root.title(f"我的记事本 - {file_path}")

def save_file(self):
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
    )
    if file_path:
        content = self.text_area.get(1.0, tk.END)
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(content)
        self.root.title(f"我的记事本 - {file_path}")

现在你有了一个能新建、打开、保存文件的记事本。已经能应对大部分日常记录了。

第三步:深色模式,保护眼睛

我是个长期面对屏幕的人,对白色背景越来越敏感。深色模式是我最想要的功能。

加一个"查看"菜单,放一个切换深色模式的选项。

ini 复制代码
def __init__(self):
    # ... 之前的代码 ...
    
    # 查看菜单
    view_menu = tk.Menu(menubar, tearoff=0)
    menubar.add_cascade(label="查看", menu=view_menu)
    view_menu.add_command(label="深色模式", command=self.toggle_dark_mode)
    
    self.dark_mode = False
    self.default_bg = "white"
    self.default_fg = "black"

def toggle_dark_mode(self):
    if self.dark_mode:
        # 切换回浅色模式
        self.text_area.config(bg="white", fg="black", insertbackground="black")
        self.dark_mode = False
    else:
        # 切换到深色模式
        self.text_area.config(bg="#1e1e1e", fg="#d4d4d4", insertbackground="white")
        self.dark_mode = True

点击一下,背景变深色,文字变成柔和的灰色,光标变成白色。晚上写东西眼睛舒服多了。

第四步:常用短语快捷输入

我经常要写一些重复的内容,比如"已收到,稍后回复"或者"项目进度正常,暂无风险"。每次都要重新打,烦得很。

加一个"工具"菜单,里面放几个常用短语的快捷按钮。

ini 复制代码
def __init__(self):
    # ... 之前的代码 ...
    
    # 工具菜单
    tools_menu = tk.Menu(menubar, tearoff=0)
    menubar.add_cascade(label="工具", menu=tools_menu)
    tools_menu.add_command(label="插入当前时间", command=self.insert_time)
    tools_menu.add_separator()
    tools_menu.add_command(label="快速回复模板", command=self.insert_reply_template)
    
def insert_time(self):
    from datetime import datetime
    now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    self.text_area.insert(tk.INSERT, now)

def insert_reply_template(self):
    template = "已收到您的消息,我会尽快处理并回复您。"
    self.text_area.insert(tk.INSERT, template)

现在写东西的时候,点一下"工具-插入当前时间",时间戳自动就出来了。模板内容也能一键插入,省了不少事。

第五步:自动保存,再也不怕忘记

用系统自带记事本最怕什么?写了半天忘了保存,电脑突然重启,全没了。

加个自动保存功能,每隔一分钟自动把内容存到备份文件里。

python 复制代码
import os
import pickle

def __init__(self):
    # ... 之前的代码 ...
    self.backup_file = "backup.pkl"
    self.load_backup()
    # 启动自动保存定时器
    self.auto_save()

def auto_save(self):
    # 每60秒自动保存一次
    content = self.text_area.get(1.0, tk.END)
    with open(self.backup_file, "wb") as f:
        pickle.dump(content, f)
    self.root.after(60000, self.auto_save)  # 60000毫秒 = 60秒

def load_backup(self):
    if os.path.exists(self.backup_file):
        try:
            with open(self.backup_file, "rb") as f:
                content = pickle.load(f)
                if content.strip():  # 只有非空内容才恢复
                    self.text_area.insert(1.0, content)
        except:
            pass

现在你写的东西每隔一分钟自动备份一次。就算程序崩溃或者电脑断电,重启后之前的内容还在。

第六步:拖拽打开文件

有时候从文件夹直接拖一个文件到记事本窗口,希望它能自动打开。这个功能用 tkinterdnd2 实现起来很简单。

先安装库:

复制代码
pip install tkinterdnd2

然后修改代码:

python 复制代码
from tkinterdnd2 import DND_FILES, TkinterDnD

class MyNotepad:
    def __init__(self):
        self.root = TkinterDnD.Tk()  # 改用支持拖拽的Tk
        # ... 其他初始化代码 ...
        
        # 注册拖拽事件
        self.text_area.drop_target_register(DND_FILES)
        self.text_area.dnd_bind('<<Drop>>', self.on_drop)
    
    def on_drop(self, event):
        file_path = event.data
        # 处理拖拽的文件路径
        if file_path.startswith('{') and file_path.endswith('}'):
            file_path = file_path[1:-1]
        try:
            with open(file_path, "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.root.title(f"我的记事本 - {file_path}")
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件:{e}")

现在直接从文件夹拖一个 txt 文件到窗口,内容就自动加载进来了。

第七步:打包成exe,发给朋友用

做好了给自己用当然没问题,但如果想分享给不会 Python 的朋友,就需要打包成 exe 文件。

pyinstaller 打包:

css 复制代码
pip install pyinstaller
pyinstaller --onefile --windowed my_notepad.py

等一两分钟,在 dist 文件夹里就能找到 my_notepad.exe,双击就能运行,不需要安装 Python。

半小时能做什么?比你想象的多

回到开头那个问题。半小时能做出一款记事本吗?

从零开始,搭窗口用了3分钟,加菜单和文件功能用了8分钟,深色模式用了3分钟,快捷输入用了5分钟,自动保存用了6分钟,拖拽功能用了5分钟。加起来刚好30分钟。

你可能会说:这不就是一个简陋的记事本吗,系统自带的不是更好?

系统自带的是够用,但自己做的有几个好处:

想要什么功能就加什么功能。今天想加个字数统计,明天想加个云同步,后天想加个密码保护,全凭自己需求来。

没有任何广告和隐私问题。代码全在自己手里,不会偷偷上传你的数据,不会在角落里塞个广告条。

真的很有成就感。这个听起来有点虚,但当你用着自己亲手写出来的软件,那种感觉确实不太一样。

完整代码在这里

python 复制代码
import tkinter as tk
from tkinter import scrolledtext, filedialog, messagebox
from tkinterdnd2 import DND_FILES, TkinterDnD
import os
import pickle
from datetime import datetime

class MyNotepad:
    def __init__(self):
        self.root = TkinterDnD.Tk()
        self.root.title("我的记事本")
        self.root.geometry("800x600")
        
        # 文本框
        self.text_area = scrolledtext.ScrolledText(
            self.root, 
            wrap=tk.WORD, 
            font=("微软雅黑", 12)
        )
        self.text_area.pack(fill=tk.BOTH, expand=True)
        
        # 拖拽支持
        self.text_area.drop_target_register(DND_FILES)
        self.text_area.dnd_bind('<<Drop>>', self.on_drop)
        
        # 菜单栏
        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_file)
        file_menu.add_command(label="打开", command=self.open_file)
        file_menu.add_command(label="保存", command=self.save_file)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        
        # 查看菜单
        view_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="查看", menu=view_menu)
        view_menu.add_command(label="深色模式", command=self.toggle_dark_mode)
        
        # 工具菜单
        tools_menu = tk.Menu(menubar, tearoff=0)
        menubar.add_cascade(label="工具", menu=tools_menu)
        tools_menu.add_command(label="插入当前时间", command=self.insert_time)
        tools_menu.add_separator()
        tools_menu.add_command(label="快速回复模板", command=self.insert_reply_template)
        
        # 状态
        self.dark_mode = False
        self.backup_file = "backup.pkl"
        
        # 恢复备份
        self.load_backup()
        # 启动自动保存
        self.auto_save()
    
    def new_file(self):
        self.text_area.delete(1.0, tk.END)
        self.root.title("我的记事本 - 新建文件")
    
    def open_file(self):
        file_path = filedialog.askopenfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            with open(file_path, "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.root.title(f"我的记事本 - {file_path}")
    
    def save_file(self):
        file_path = filedialog.asksaveasfilename(
            defaultextension=".txt",
            filetypes=[("文本文件", "*.txt"), ("所有文件", "*.*")]
        )
        if file_path:
            content = self.text_area.get(1.0, tk.END)
            with open(file_path, "w", encoding="utf-8") as f:
                f.write(content)
            self.root.title(f"我的记事本 - {file_path}")
    
    def toggle_dark_mode(self):
        if self.dark_mode:
            self.text_area.config(bg="white", fg="black", insertbackground="black")
            self.dark_mode = False
        else:
            self.text_area.config(bg="#1e1e1e", fg="#d4d4d4", insertbackground="white")
            self.dark_mode = True
    
    def insert_time(self):
        now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        self.text_area.insert(tk.INSERT, now)
    
    def insert_reply_template(self):
        template = "已收到您的消息,我会尽快处理并回复您。"
        self.text_area.insert(tk.INSERT, template)
    
    def auto_save(self):
        content = self.text_area.get(1.0, tk.END)
        with open(self.backup_file, "wb") as f:
            pickle.dump(content, f)
        self.root.after(60000, self.auto_save)
    
    def load_backup(self):
        if os.path.exists(self.backup_file):
            try:
                with open(self.backup_file, "rb") as f:
                    content = pickle.load(f)
                    if content.strip():
                        self.text_area.insert(1.0, content)
            except:
                pass
    
    def on_drop(self, event):
        file_path = event.data
        if file_path.startswith('{') and file_path.endswith('}'):
            file_path = file_path[1:-1]
        try:
            with open(file_path, "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.root.title(f"我的记事本 - {file_path}")
        except Exception as e:
            messagebox.showerror("错误", f"无法打开文件:{e}")
    
    def run(self):
        self.root.mainloop()

if __name__ == "__main__":
    app = MyNotepad()
    app.run()

把这段代码保存,运行,你的专属记事本就诞生了。

最后说一句

技术这东西,很多时候不是你不会,而是你觉得"这事肯定很复杂"所以一直没动手。

等你真的坐下来,一行一行敲出来,跑起来的那一刻,你会发现:原来我也能做到。

这个记事本只是个起点。你可以继续往上加功能:加个加密功能保护隐私,加个云同步在多台设备间共享,甚至做成一个简单的 Markdown 编辑器。

从一个小需求开始,亲手把它实现出来,这个过程本身就是编程最有趣的部分。

相关推荐
曲幽2 小时前
FastAPI里玩转Redis和数据库的正确姿势,别让异步任务把你坑哭了!
redis·python·mysql·fastapi·web·celery·sqlalchemy·task·backgroundtask
未知鱼2 小时前
Python安全开发之简易csrf检测工具
python·安全·csrf
何政@2 小时前
Agent Skills 完全指南:从概念到自定义实践
人工智能·python·大模型·claw·404 not found 罗
AmyLin_20012 小时前
【pdf2md-3:实现揭秘】福昕PDF SDK Python 开发实战:从逐字符提取到 LR 版面分析
开发语言·python·pdf·sdk·markdown·pdf2md
IP老炮不瞎唠2 小时前
Scrapy 高效采集:优化方案与指南
网络·爬虫·python·scrapy·安全
沪漂阿龙2 小时前
深入浅出 Pandas apply():从入门到向量化思维
人工智能·python·pandas
我材不敲代码2 小时前
OpenCV 实战——Python 实现图片人脸检测 + 视频人脸微笑检测
人工智能·python·opencv
七夜zippoe3 小时前
模型部署优化:ONNX与TensorRT实战——从训练到推理的完整优化链路
人工智能·python·tensorflow·tensorrt·onnx
maxmaxma3 小时前
ROS2 机器人 少年创客营:Day 7
人工智能·python·机器人·ros2