那天下午,我对着电脑屏幕发呆
事情是这样的。
上周三下午,我正写着代码,突然需要记点东西。打开系统自带的记事本,白底黑字,功能倒是够用,但总觉得哪里不对劲。我想要个深色背景保护眼睛,想把常用短语存成快捷按钮,想随手记录的时候自动加上时间戳。
打开软件商店搜了一圈,免费的要么带广告,要么功能臃肿得像个航母。付费的倒是有几个不错的,可为了这点小需求花几十块钱,总觉得不太划算。
我看了眼时间,下午三点。离下班还有两个小时。
一个念头冒了出来:干脆自己写一个。
为什么自己写?因为真的不难
很多人听到"自己做软件"就觉得是件大事,要学一堆框架,要懂什么设计模式,要会各种高深的技术。
真不是。
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 编辑器。
从一个小需求开始,亲手把它实现出来,这个过程本身就是编程最有趣的部分。