阶段一实战项目:仿照记事本开发简易文本编辑器(PyQt5完整代码)

寒烟似雪
1年前发布 /正在检测是否收录...

阶段一实战项目:仿照记事本界面开发简易文本编辑器

哈喽~ 欢迎来到PyQt5系列的第5篇——阶段一实战项目!经过前4篇的学习,我们已经掌握了QWidget基础窗口、线性布局(QVBoxLayout/QHBoxLayout)、核心基础控件(标签、按钮、输入框、复选框等)以及信号与槽的基础用法。今天我们将把这些知识点整合起来,仿照Windows记事本的核心界面与基础功能,开发一个简易文本编辑器,实现“新建、打开、保存文本”“文本编辑”“字体加粗”等核心功能,让你快速掌握知识点的综合应用!
mjr0cjri.png

一、项目需求分析:仿照记事本核心功能

我们聚焦Windows记事本的核心功能,本次项目实现以下需求:

  • 界面需求:仿照记事本布局,包含“功能按钮区”(新建、打开、保存、字体加粗)和“文本编辑区”(多行文本输入/显示);
  • 核心功能:新建空白文本、打开本地文本文件、保存文本到本地、文本加粗编辑;
  • 交互需求:按钮点击反馈、打开/保存文件弹窗提示、文本编辑实时响应;
  • 适配需求:窗口缩放时,文本编辑区自适应调整大小。

【界面参考】Windows记事本核心布局:顶部功能按钮区 + 中间大面积文本编辑区,我们简化实现核心按钮,保证界面简洁且功能完整。
mjr06wos.png

二、技术选型:贴合阶段一知识点

本次项目严格基于阶段一所学知识点,不引入新的复杂组件,技术栈如下:

  • 窗口组件:QWidget(主窗口);
  • 布局管理器:QVBoxLayout(垂直布局,管理按钮区和编辑区)、QHBoxLayout(水平布局,排列功能按钮);
  • 核心控件:QPushButton(功能按钮)、QTextEdit(多行文本编辑区)、QCheckBox(字体加粗选择框);
  • 交互核心:信号与槽(按钮点击、复选框状态变化绑定对应功能);
  • 文件操作:基础文件读写(结合Python内置open函数)。

三、界面设计与实现步骤

我们采用“先搭框架,再填功能”的思路,分3步实现:

  1. 搭建主窗口与布局(垂直布局+水平布局组合);
  2. 添加控件(功能按钮、复选框、文本编辑区)并绑定布局;
  3. 实现控件信号与槽绑定,编写功能逻辑。

四、完整代码实现(可直接运行)

mjr0a9z8.png

import sys
import os
from PyQt5.QtWidgets import (
    QApplication, QWidget, QPushButton, QTextEdit,
    QCheckBox, QVBoxLayout, QHBoxLayout, QFileDialog
)
from PyQt5.QtGui import QFont
from PyQt5.QtCore import Qt

class SimpleNotepad(QWidget):
    def __init__(self):
        super().__init__()
        # 初始化窗口基础属性
        self.init_window()
        # 初始化控件与布局结构
        self.init_widgets_layout()
        # 绑定信号与槽函数
        self.init_signals_slots()
        # 记录当前打开的文件路径,初始为None表示新文件
        self.current_file_path = None

    def init_window(self):
        """初始化窗口的标题、大小和位置"""
        self.setWindowTitle("简易文本编辑器(仿照记事本)")
        # 设置窗口初始尺寸
        self.resize(800, 600)
        # 计算并设置窗口居中显示
        screen_geometry = QApplication.desktop().availableGeometry()
        x = (screen_geometry.width() - self.width()) // 2
        y = (screen_geometry.height() - self.height()) // 2
        self.move(x, y)

    def init_widgets_layout(self):
        """创建所有界面控件并设置布局"""
        # 创建主垂直布局,设置控件间距和窗口内边距
        self.main_layout = QVBoxLayout()
        self.main_layout.setSpacing(10)
        self.main_layout.setContentsMargins(15, 15, 15, 15)

        # 创建按钮区水平布局
        self.button_layout = QHBoxLayout()
        self.button_layout.setSpacing(10)

        # 创建功能按钮并设置固定尺寸
        self.new_btn = QPushButton("新建")
        self.open_btn = QPushButton("打开")
        self.save_btn = QPushButton("保存")
        btn_size = (80, 30)
        self.new_btn.setFixedSize(*btn_size)
        self.open_btn.setFixedSize(*btn_size)
        self.save_btn.setFixedSize(*btn_size)

        # 创建字体加粗复选框,设置文本居中显示
        self.bold_check = QCheckBox("字体加粗")
        self.bold_check.setStyleSheet("text-align: center;")

        # 将按钮添加到水平布局
        self.button_layout.addWidget(self.new_btn)
        self.button_layout.addWidget(self.open_btn)
        self.button_layout.addWidget(self.save_btn)
        # 添加伸缩项,将复选框推至布局右侧
        self.button_layout.addStretch()
        self.button_layout.addWidget(self.bold_check)

        # 创建文本编辑区域,设置默认字体和占位提示文本
        self.text_edit = QTextEdit()
        self.text_edit.setFont(QFont("微软雅黑", 12))
        self.text_edit.setPlaceholderText("请输入文本内容...(支持新建、打开、保存文件)")

        # 将按钮布局和文本编辑区添加到主布局
        self.main_layout.addLayout(self.button_layout)
        self.main_layout.addWidget(self.text_edit)

        # 设置窗口的主布局
        self.setLayout(self.main_layout)

    def init_signals_slots(self):
        """绑定控件的信号与对应的槽函数"""
        self.new_btn.clicked.connect(self.on_new_click)
        self.open_btn.clicked.connect(self.on_open_click)
        self.save_btn.clicked.connect(self.on_save_click)
        self.bold_check.stateChanged.connect(self.on_bold_check_change)

    def on_new_click(self):
        """新建文件:清空编辑区,重置文件路径"""
        # 若有未保存内容,先提示保存
        if self.text_edit.toPlainText() and not self.current_file_path:
            reply = QFileDialog.getSaveFileName(self, "保存当前内容", "", "Text Files (*.txt)")
            if reply[0]:
                self.save_text_to_file(reply[0])
        # 清空编辑区内容
        self.text_edit.clear()
        # 重置当前文件路径
        self.current_file_path = None
        # 更新窗口标题
        self.setWindowTitle("简易文本编辑器(仿照记事本)- 未保存文件")

    def on_open_click(self):
        """打开文件:选择txt文件并读取内容到编辑区"""
        # 弹出文件选择对话框,筛选文本文件
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "打开文本文件",
            "",
            "Text Files (*.txt);;All Files (*.*)"
        )
        # 验证文件路径有效性并读取内容
        if file_path and os.path.exists(file_path):
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
            self.text_edit.setText(content)
            self.current_file_path = file_path
            # 更新窗口标题显示当前文件名
            self.setWindowTitle(f"简易文本编辑器(仿照记事本)- {os.path.basename(file_path)}")

    def on_save_click(self):
        """保存文件:已有路径则直接保存,无路径则弹出保存对话框"""
        if self.current_file_path:
            # 直接保存到当前路径
            self.save_text_to_file(self.current_file_path)
        else:
            # 弹出保存对话框选择路径
            file_path, _ = QFileDialog.getSaveFileName(
                self,
                "保存文本文件",
                "",
                "Text Files (*.txt)"
            )
            if file_path:
                # 自动补充txt后缀
                if not file_path.endswith(".txt"):
                    file_path += ".txt"
                self.save_text_to_file(file_path)
                self.current_file_path = file_path
                self.setWindowTitle(f"简易文本编辑器(仿照记事本)- {os.path.basename(file_path)}")

    def save_text_to_file(self, file_path):
        """将编辑区内容写入指定路径的文件"""
        content = self.text_edit.toPlainText()
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(content)

    def on_bold_check_change(self, state):
        """根据复选框状态切换编辑区文本的加粗样式"""
        current_font = self.text_edit.font()
        # Qt.Checked对应值为2,Qt.Unchecked对应值为0
        current_font.setBold(state == Qt.Checked)
        self.text_edit.setFont(current_font)

if __name__ == "__main__":
    # 创建应用程序实例
    app = QApplication(sys.argv)
    # 创建记事本窗口实例
    notepad = SimpleNotepad()
    # 显示窗口
    notepad.show()
    # 启动应用程序主循环
    sys.exit(app.exec_())

五、代码逐行解析(核心部分)

1. 类结构与初始化流程

我们将所有功能封装到SimpleNotepad类(继承QWidget),初始化流程分3步:

  • init_window():设置窗口标题、大小、居中显示,提升用户体验;
  • init_widgets_layout():核心布局搭建,用“垂直布局+水平布局”组合实现记事本风格,按钮区在上、编辑区在下,保证窗口缩放时编辑区自适应;
  • init_signals_slots():绑定所有控件的信号与槽,实现“点击按钮触发功能”“复选框变化触发字体调整”。

2. 布局核心逻辑

采用“嵌套布局”思路,解决控件排列问题:

  • 主布局(QVBoxLayout):垂直方向排列“按钮布局”和“文本编辑区”,addStretch()未使用,让编辑区占满剩余空间;
  • 按钮布局(QHBoxLayout):水平方向排列3个功能按钮,添加addStretch()伸缩空间将“字体加粗”复选框推到右侧,让布局更美观。

3. 核心功能实现

(1)新建文件(on_new_click)

逻辑:先判断当前是否有未保存的内容,如果有则弹出保存对话框;清空编辑区,重置current_file_path(标记为新文件),更新窗口标题。

(2)打开文件(on_open_click)

逻辑:用QFileDialog.getOpenFileName()弹出文件选择框,筛选txt文件;读取选中文件的内容并显示到QTextEdit,更新current_file_path和窗口标题(显示文件名)。

(3)保存文件(on_save_click)

逻辑:如果已打开文件(current_file_path不为None),直接保存;否则弹出保存对话框,让用户选择路径,补充.txt后缀,保存内容后更新路径和标题。

(4)字体加粗(on_bold_check_change)

逻辑:监听复选框状态变化,用QFont.setBold()切换字体加粗状态,直接作用于QTextEdit的当前字体。

六、运行效果与测试步骤

1. 运行方式

将代码保存为simple_notepad.py,确保已安装PyQt5,终端运行命令:


python simple_notepad.py  # Windows
python3 simple_notepad.py  # macOS/Linux

2. 测试步骤

  1. 测试新建:点击“新建”,编辑区清空,标题显示“未保存文件”;
  2. 测试打开:点击“打开”,选择本地txt文件,内容正常显示,标题显示文件名;
  3. 测试保存:编辑内容后点击“保存”,如果是新文件则弹出保存对话框,保存后可在对应路径找到txt文件;
  4. 测试字体加粗:勾选“字体加粗”,编辑区文本变为加粗;取消勾选则恢复正常。

七、常见问题排查

  • 问题1:打开文件后中文乱码 → 解决:读取文件时指定encoding="utf-8",保存时也用utf-8编码;
  • 问题2:窗口缩放时编辑区不自适应 → 解决:确保主布局是QVBoxLayout,且QTextEdit直接添加到主布局(未设置固定大小);
  • 问题3:保存文件后没有.txt后缀 → 解决:代码中已添加判断,自动补充.txt后缀,无需手动输入;
  • 问题4:按钮点击无反应 → 解决:检查信号与槽绑定是否正确(如self.new_btn.clicked.connect(self.on_new_click)是否写错函数名)。

八、功能拓展思路(阶段一知识点范围内)

如果想进一步练习,可以基于当前代码拓展以下功能:

  • 添加“撤销/重做”按钮:利用QTextEdit.undo()QTextEdit.redo()实现;
  • 添加“清空”按钮:绑定self.text_edit.clear()
  • 添加“字体大小调整”:用QComboBox下拉选择字体大小,绑定信号修改QFontsetPointSize()
  • 添加“换行/不换行”复选框:用QTextEdit.setLineWrapMode()控制换行模式。

总结

本次项目完美整合了阶段一的核心知识点:窗口设置、线性布局、基础控件使用、信号与槽绑定。通过仿照记事本界面开发,你应该能深刻理解“布局管理器解决控件排列”“信号与槽实现交互”的核心逻辑。

下一篇我们将进入阶段二,学习网格布局、表单布局等进阶布局管理器,为更复杂的界面开发打基础。如果在项目实操中遇到问题,或者有拓展功能的想法,欢迎在评论区留言讨论~

© 版权声明
THE END
喜欢就支持一下吧
点赞 0 分享 收藏
评论 抢沙发
OωO
取消
SSL