🇯🇵 日本語 | 🇺🇸 English | 🇪🇸 Español | 🇵🇹 Português | 🇹🇭 ไทย | 🇨🇳 中文

【一键复制运行】来用Python制作一个简单的记事本应用吧!(带文件保存功能)

“想用编程做点能看得见摸得着的东西!”

致这么想的你。在本文中,我将用全世界最通俗易懂的方式,解说如何使用Python编程语言,制作一个可以输入文字并保存到文件的、属于你自己的简单“记事本应用”。

你好!我是一个几个月前还对编程一无所知的自学开发者,目前正借助AI的力量进行学习。我一开始也是“文件保存?这是什么咒语吗?”的水平(笑)。正因如此,我希望尽可能不使用专业术语,以一个曾经的初学者的视角,和大家分享我踩过的坑,一起前进。

本文的目标只有一个,那就是让你体验到“我自己写的程序成功运行了!”的感动。因此,我们把难懂的部分往后放!首先,让我们来试试复制粘贴就能运行的成品吧!


第1步:马上动手试试!完整代码在此

百闻不如一见。首先,请将下面的代码全部复制,保存为名为memo_app.py的文件,然后运行它。还没有Python运行环境的朋友,请先准备好哦。

如果你在想“咦,直接就是成品了?”“解说呢?”,那你就想对啦!首先体验到“程序能动起来”的成功感,是让编程变得有趣的最大秘诀。


import tkinter as tk
import tkinter.filedialog as filedialog

def save_file():
    """保存文件的函数"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("文本文档", "*.txt"), ("所有文件", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        print(f"发生了错误: {e}")

def open_file():
    """打开文件的函数"""
    file_path = filedialog.askopenfilename(
        filetypes=[("文本文档", "*.txt"), ("所有文件", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            text_content = file.read()
            text_area.delete(1.0, tk.END)
            text_area.insert(tk.END, text_content)
    except Exception as e:
        print(f"发生了错误: {e}")

# 创建主窗口
window = tk.Tk()
window.title("简单的记事本")
window.geometry("600x400")

# 创建文本输入区
text_area = tk.Text(window, wrap=tk.WORD)
text_area.pack(expand=True, fill=tk.BOTH)

# 创建菜单栏
menu_bar = tk.Menu(window)
window.config(menu=menu_bar)

# 创建“文件”菜单
file_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="打开...", command=open_file)
file_menu.add_command(label="另存为...", command=save_file)
file_menu.add_separator()
file_menu.add_command(label="退出", command=window.quit)

# 显示窗口
window.mainloop()
    

怎么样?如果出现了这样的窗口,就说明你大功告成啦!

使用Python创建的简单记事本应用的屏幕截图。窗口顶部有一个“文件”菜单,中央有一个大的文本输入区域。

试着输入一些文字,或者从菜单中选择“另存为...”和“打开...”。它能作为一个记事本正常工作,是不是有点小激动呢?


第2步:代码探险!一探究竟它是如何工作的

体验过“成功运行!”的喜悦后,接下来让我们一起探索“它为什么能工作?”。我们会把刚才的代码拆分成几个部分,逐一解说每个部分的作用。

① 准备魔法工具箱 (import)

代码的头两行,就像是让Python加载我们接下来要用的“便利工具”的咒语。


import tkinter as tk
import tkinter.filedialog as filedialog
    

② 搭建应用的地基 (创建窗口)

接下来,我们来创建应用的主窗口。如果把这比作盖房子,这部分就相当于打地基和搭框架。


# 创建主窗口
window = tk.Tk()
window.title("简单的记事本")
window.geometry("600x400")

# ... (省略) ...

# 显示窗口
window.mainloop()
    

③ 准备一个写字的地方 (文本区域)

既然是记事本,当然需要一个输入文字的空间。创建这个空间的就是这部分代码。


# 创建文本输入区
text_area = tk.Text(window, wrap=tk.WORD)
text_area.pack(expand=True, fill=tk.BOTH)
    

④ 创建指令的集合体 (函数)

终于到了这个应用的心脏部分,也就是“打开文件”和“保存文件”的具体处理逻辑。这些处理过程被定义为函数,它就像一个“汇集了多条指令的便利箱子”。

保存文件:`save_file()` 函数


def save_file():
    """保存文件的函数"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("文本文档", "*.txt"), ("所有文件", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        print(f"发生了错误: {e}")
    

这段代码包含了很多要点。

  1. `filedialog.asksaveasfilename(...)`: 这就是显示“另存为”对话框的命令。用户选择的保存位置路径(就像是通往文件的地址)会被存入名为`file_path`的变量中。
  2. `if not file_path: return`: 如果用户在对话框中点击了“取消”,`file_path`就会是空的。这时,这关键的一行会让函数直接结束,不执行任何操作。
  3. `with open(file_path, 'w', encoding='utf-8') as file:`: 这里是文件输入输出的核心!
    • `open()`: 按指定的模式打开指定路径的文件的命令。
    • `'w'`: 表示`write`(写入)模式。如果文件不存在,则新建;如果存在,则覆盖。
    • `encoding='utf-8'`: 这是防止乱码的超重要“咒语”。它指定使用“UTF-8”,这是一种能正确处理世界上几乎所有语言的标准字符编码。不写这一句的话,中文可能就无法正确保存。
    • `with ... as file:`: 使用这个语法,可以确保在代码块内的处理结束后,文件会被自动关闭。忘记关闭文件可能会导致内存泄漏等问题,因此这是一种非常安全且被推荐的写法。(官方文档也推荐)
  4. `text_area.get(1.0, tk.END)`: 获取文本区域中输入的所有文本
  5. `file.write(text_content)`: 将获取到的文本写入打开的文件中。

同样地,打开文件的`open_file()`函数也只是使用`'r'`(read:读取模式)来读取文件内容,并将其显示在文本区域里。机制几乎是一样的!


第3步:应用篇!打造你自己的专属记事本

了解了基本原理之后,接下来我们来玩点更有趣的!只需添加少量代码,就能实现一些便利的功能。

改造示例①:实现暗黑模式风格的设计

最近流行的暗黑模式,对眼睛更友好。我们来试试把设计改成暗黑模式吧。只需要在创建`window`和`text_area`的地方,指定背景色和文字颜色就行了。


# 创建主窗口
window = tk.Tk()
window.title("暗黑模式记事本")
window.geometry("600x400")
window.config(bg="#2d2d2d") # 添加窗口背景色

# 创建文本输入区
text_area = tk.Text(
    window, 
    wrap=tk.WORD,
    bg="#1e1e1e",          # 文本区域背景色
    fg="#dcdcdc",          # 文字颜色
    insertbackground="#ffffff" # 光标颜色
)
text_area.pack(expand=True, fill=tk.BOTH)
    

仅此而已,是不是瞬间就有现代感了!


改造示例②:添加快捷键

每次都去点菜单太麻烦了对吧。我们来实现用“Ctrl + S”保存,用“Ctrl + O”打开。在添加菜单项时,用`accelerator`写明快捷键,然后用`window.bind`将实际的按键操作和函数关联起来。

首先,像这样修改创建菜单的部分。


# 创建“文件”菜单
file_menu = tk.Menu(menu_bar, tearoff=0)
menu_bar.add_cascade(label="文件", menu=file_menu)
# 使用accelerator来提示快捷键
file_menu.add_command(label="打开...", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="另存为...", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="退出", command=window.quit)
    

接下来,在`window.mainloop()`之前,添加关联按键操作和函数的处理。


# 绑定快捷键
# 使用lambda来接收事件参数
window.bind("<Control-s>", lambda event: save_file())
window.bind("<Control-o>", lambda event: open_file())

# 显示窗口
window.mainloop()
    

`bind`方法会在事件(这次是按键)发生时调用一个函数,但同时会传递一个包含事件信息的参数(`event`对象)。然而,我们的`save_file`和`open_file`函数设计上是不接收参数的。因此,我们使用`lambda event:`来充当一个中间人,它会接收并忽略这个参数,然后调用我们想要的目标函数。这是个不错的小技巧哦!


注意事项(防患于未然)

文件操作是很容易出现意外错误的地方。我当初也曾无数次看着错误信息挠头……只要了解一些代表性的错误,就能在遇到时保持镇静。

在我们的代码中,使用了`try...except`块来捕获错误,所以万一发生错误,应用也不会崩溃,而是在控制台显示错误信息。这也是编写安全程序的一个重要技巧。


总结:小小的成功是迈向下一步的巨大动力

辛苦啦!这次我们使用Python的`Tkinter`,创建了一个带文件保存功能的简单记事本应用。

从复制粘贴开始,到理解其工作原理,最后亲手进行改造,你是否都体验到了呢?“自己写的代码,以看得见的形式动了起来”的经历,是任何东西都无法替代的喜悦,也是持续学习编程的最佳动力。

这次制作的应用仅仅是个开始。搜索功能、字数统计、自动保存等等,只要你有想法,就可以无限地添加功能。请务必以本文为基础,挑战开发你自己的原创应用吧!

下一步

了解了GUI应用的基础后,接下来想不想试试操纵“时间”呢?在下一篇文章中,我们将解说如何使用Python的`time`模块,制作一个能在指定时间提醒你的计时器应用。一起来挑战制作闹钟、番茄钟等日常实用工具吧!

→ 来用Python制作一个计时器应用吧(time模块)

附赠:可完整运行的Python代码

这是集成了本文解说的暗黑模式风格设计和快捷键应用示例的最终完整版Python代码。只要复制粘贴这个,你马上就能用上一个功能强大的记事本应用!

<?php
/*
这是一个Python脚本,而不是在Web服务器上运行的PHP文件。
请将扩展名更改为.py,并使用Python解释器运行它。
示例: python your_file_name.py
*/
?>
import tkinter as tk
import tkinter.filedialog as filedialog

def save_file():
    """保存文件的函数"""
    file_path = filedialog.asksaveasfilename(
        defaultextension=".txt",
        filetypes=[("文本文档", "*.txt"), ("所有文件", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'w', encoding='utf-8') as file:
            text_content = text_area.get(1.0, tk.END)
            file.write(text_content)
    except Exception as e:
        # 理想情况下,应该将其输出到日志或通过对话框通知用户
        print(f"发生了错误: {e}")
        window.title(f"错误: {e}")


def open_file():
    """打开文件的函数"""
    file_path = filedialog.askopenfilename(
        filetypes=[("文本文档", "*.txt"), ("所有文件", "*.*")]
    )
    if not file_path:
        return
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            text_content = file.read()
            text_area.delete(1.0, tk.END)
            text_area.insert(tk.END, text_content)
            window.title(f"记事本 - {file_path}")
    except Exception as e:
        print(f"发生了错误: {e}")
        window.title(f"错误: {e}")


# --- GUI设置 ---

# 创建主窗口
window = tk.Tk()
window.title("高级记事本")
window.geometry("800x600")
window.config(bg="#2d2d2d") # 窗口背景色

# 创建文本输入区
text_area = tk.Text(
    window,
    wrap=tk.WORD,
    bg="#1e1e1e",          # 文本区域背景色
    fg="#dcdcdc",          # 文字颜色
    insertbackground="#ffffff", # 光标颜色(白色以便查看)
    undo=True,             # 启用撤销/重做功能
    autoseparators=True
)
text_area.pack(expand=True, fill=tk.BOTH, padx=5, pady=5)


# 创建菜单栏
menu_bar = tk.Menu(window)
window.config(menu=menu_bar)

# 创建“文件”菜单
file_menu = tk.Menu(menu_bar, tearoff=0, bg="#2d2d2d", fg="#dcdcdc")
menu_bar.add_cascade(label="文件", menu=file_menu)
file_menu.add_command(label="打开...", command=open_file, accelerator="Ctrl+O")
file_menu.add_command(label="另存为...", command=save_file, accelerator="Ctrl+S")
file_menu.add_separator()
file_menu.add_command(label="退出", command=window.quit)

# 绑定快捷键 (使用lambda忽略事件参数)
window.bind("<Control-s>", lambda event: save_file())
window.bind("<Control-o>", lambda event: open_file())
window.bind("<Control-S>", lambda event: save_file()) # 也支持同时按下Shift键
window.bind("<Control-O>", lambda event: open_file()) # 也支持同时按下Shift键

# 启动窗口的显示循环
window.mainloop()