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


🌟 《零基础手把手:用 Python 30 分钟做出自己的记事本》

—— 不是照抄代码,而是理解每行代码的「灵魂」


🧩 第一步:为什么我们需要「基础窗口」?(新手必懂!)

❌ 常见错误:直接写 window.show() 但窗口不显示?

✅ 正确逻辑:程序运行流程图

启动程序

创建应用对象

创建窗口

显示窗口

进入事件循环

📝 代码详解(逐行解释):

import sys # 必须!用于接收系统参数(比如文件路径)from PyQt6.QtWidgets import QApplication, QMainWindow # 从PyQt库导入两个核心组件# 1️⃣ 创建应用对象(灵魂!所有PyQt程序必须有) app = QApplication(sys.argv)# sys.argv = 系统传递的命令行参数(比如打开的文件名)# 2️⃣ 创建主窗口(你的「画布」) window = QMainWindow()# 100% 会用到的窗口类型 window.setWindowTitle("我的迷你记事本")# 设置标题(为什么叫"窗口"?因为它是所有UI的容器!) window.resize(500,400)# 设置大小(宽500px, 高400px)# 3️⃣ 显示窗口(关键!) window.show()# ✨ 为什么必须写?因为窗口默认是「隐形」的!# ❌ 如果不写这行,程序会直接结束,你永远看不到窗口!# 4️⃣ 进入事件循环(让程序「活」起来) sys.exit(app.exec())# ✨ 为什么叫「事件循环」?因为程序会一直监听用户操作(点击、输入等)

💡 思考题

❓ 如果我删掉 sys.exit(app.exec()) 会怎样?
答案:程序会立刻结束!你只能看到一闪而过的窗口(就像打开一个网页立刻关闭)。

🧩 第二步:为什么需要 QTextEdit?(小白必看!)

❌ 常见错误:用 QLineEdit(单行输入框)做记事本 → 无法输入多行文字!

✅ 正确选择:QTextEdit = 专为多行文本设计的编辑器

📝 代码详解(添加编辑器):

from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit # 新增导入 app = QApplication(sys.argv) window = QMainWindow() window.setWindowTitle("我的迷你记事本") window.resize(700,500)# 宽高调大一点(记事本需要更多空间)# ✨ 关键步骤:把编辑器设置为窗口的「中央内容」 editor = QTextEdit()# 创建编辑器对象 window.setCentralWidget(editor)# 设置为窗口的主区域# ✨ 为什么叫「中央」?因为窗口可以有顶部菜单、底部状态栏,编辑器占中间大块

💡 思考题

❓ 如果我把 window.setCentralWidget(editor) 写成 window.setWidget(editor) 会怎样?
答案:报错!setCentralWidget 是 QMainWindow 的专属方法(PyQt 设计的规范)。

🧩 第三步:菜单栏怎么设计?(不是复制粘贴!)

❌ 常见错误:直接写 menubar = menuBar() → 无菜单!

✅ 正确逻辑:菜单 = 1个主菜单 + 多个子菜单项

📝 代码详解(分步构建菜单):

# 1️⃣ 创建菜单栏(必须先有窗口才有菜单栏) menubar = window.menuBar()# 获取窗口的菜单栏对象# 2️⃣ 添加「文件」主菜单(为什么叫「主菜单」?因为它在最左边) file_menu = menubar.addMenu("文件")# 创建菜单项# 3️⃣ 在「文件」里添加子菜单(每个子菜单是用户点击的按钮) open_action = file_menu.addAction("打开文件")# 添加「打开」按钮 save_action = file_menu.addAction("保存文件")# 添加「保存」按钮# 4️⃣ 设置快捷键(为什么需要?因为用户习惯Ctrl+S!) save_action.setShortcut("Ctrl+S")# 40% 用户会用快捷键

💡 思考题

❓ 为什么「打开」和「保存」要用 addAction 而不是 addButton
答案QAction 是 PyQt 的统一事件处理单元(不是按钮!),它能绑定到菜单/按钮/工具栏。

🧩 第四步:实现「打开文件」功能(关键!)

❌ 常见错误:忘记 with open → 文件没关闭 → 内存泄漏!

✅ 正确逻辑:用户点击 → 弹出文件选择框 → 读取文件 → 显示到编辑器

📝 代码详解(带思考注释):

defopen_file(self):# ✨ 为什么用 QFileDialog.getOpenFileName?因为这是PyQt的标准文件选择器 path, _ = QFileDialog.getOpenFileName( self,# 父窗口(确保弹窗在记事本内部)"打开文件",# 窗口标题"",# 默认打开路径(留空表示当前目录)"Text Files (*.txt);;All Files (*)"# 文件过滤器(显示.txt和所有文件))# ✨ 为什么需要检查 path?因为用户可能点了「取消」!if path:# ✨ 为什么用 'r' 和 utf-8?因为读取文本文件,且支持中文withopen(path,'r', encoding='utf-8')as f: self.editor.setText(f.read())# 将文件内容放入编辑器# ✨ 为什么更新状态栏?让用户知道发生了什么 self.statusBar().showMessage(f"已打开: {path}")

💡 思考题

❓ 如果用户打开一个 .jpg 文件会怎样?
答案:程序会崩溃!因为 f.read() 读的是二进制,不是文本。这就是为什么需要文件过滤器"Text Files (*.txt)")。

🧩 第五步:实现「字数统计」(小白最爱的功能!)

❌ 常见错误:用 self.editor.text() → 会包含HTML标签!

✅ 正确逻辑:实时监听文字变化 → 计算纯文本字数

📝 代码详解(关键在 textChanged 信号):

# 1️⃣ 初始化状态栏(在 initUI 里) self.statusBar().showMessage("准备就绪")# 初始状态# 2️⃣ 监听文字变化(核心!) self.editor.textChanged.connect(self.update_status)# 当文字变化时,自动调用 update_status# 3️⃣ 实现统计函数defupdate_status(self): text = self.editor.toPlainText()# ✨ 为什么用 toPlainText?因为这是纯文本! char_count =len(text)# 字符数(含空格) line_count =len(text.split('\n'))# 行数(按换行符分割)# 更新状态栏(为什么用 f-string?因为可读性高!) self.statusBar().showMessage(f"字数: {char_count} | 行数: {line_count}")

💡 思考题

❓ 为什么 text.split('\n') 能算行数?如果用户用的是 \r\n(Windows换行符)会怎样?
答案split('\n') 会把 \r\n 当成两个字符,导致行数多1。正确做法:用 text.splitlines()(PyQt内置方法,自动处理换行符)。

🧩 第六步:为什么需要「类结构」?(小白的终极困惑)

❌ 常见错误:把所有代码写在全局(导致变量混乱!)

✅ 正确逻辑:用类封装所有功能 → 代码清晰 + 方便绑定槽函数

📝 为什么这样写?

classSimplePad(QMainWindow):# 继承自QMainWindow(让记事本拥有窗口能力)def__init__(self):super().__init__()# 初始化父类(必须!) self.initUI()# 自己写的初始化方法definitUI(self):# 这里放所有界面初始化代码(窗口、编辑器、菜单等)# ✨ 为什么不用全局变量?因为:1. 代码可读性高 2. 便于多人协作 3. 避免变量覆盖

💡 思考题

❓ 如果我删掉 super().__init__() 会怎样?
答案:窗口会报错!因为 QMainWindow 的初始化逻辑没执行(PyQt要求必须调用父类构造函数)。

✅ 最终代码(完整版,带详细注释)

import sys from PyQt6.QtWidgets import QApplication, QMainWindow, QTextEdit, QFileDialog, QFontDialog, QMenuBar, QStatusBar classSimplePad(QMainWindow):def__init__(self):super().__init__()# 1️⃣ 必须初始化父类 self.initUI()# 2️⃣ 初始化界面definitUI(self):# 🔧 1. 设置窗口基础属性 self.setWindowTitle("SimplePad - 我的第一个记事本") self.resize(800,600)# 更大的窗口(方便看字数)# 📝 2. 创建文本编辑器(核心!) self.editor = QTextEdit() self.setCentralWidget(self.editor)# 设置为窗口中央内容# 📋 3. 创建菜单栏(分步骤构建) menubar = self.menuBar()# 获取菜单栏# 文件菜单 file_menu = menubar.addMenu("文件") file_menu.addAction("新建").triggered.connect(self.editor.clear)# 新建 → 清空 file_menu.addAction("打开").triggered.connect(self.open_file)# 打开 → 绑定函数 save_action = file_menu.addAction("保存") save_action.setShortcut("Ctrl+S")# 快捷键 save_action.triggered.connect(self.save_file)# 保存 → 绑定函数# 格式菜单 format_menu = menubar.addMenu("格式") format_menu.addAction("字体设置").triggered.connect(self.change_font)# 📊 4. 状态栏(字数统计) self.statusBar().showMessage("准备就绪") self.editor.textChanged.connect(self.update_status)# 关键!监听文字变化# ⚙️ 5. 打开文件(带错误处理)defopen_file(self): path, _ = QFileDialog.getOpenFileName( self,"打开文件","","Text Files (*.txt);;All Files (*)")if path:# ✅ 检查用户是否选择了文件withopen(path,'r', encoding='utf-8')as f: self.editor.setText(f.read()) self.statusBar().showMessage(f"已打开: {path}")# 📦 6. 保存文件(带用户友好提示)defsave_file(self): path, _ = QFileDialog.getSaveFileName( self,"保存文件","","Text Files (*.txt)")if path: content = self.editor.toPlainText()# ✨ 纯文本!withopen(path,'w', encoding='utf-8')as f: f.write(content) self.statusBar().showMessage(f"已保存: {path}")# 🎨 7. 字体设置(用标准对话框)defchange_font(self): font, ok = QFontDialog.getFont()if ok: self.editor.setFont(font)# 📊 8. 字数统计(实时更新!)defupdate_status(self): text = self.editor.toPlainText() char_count =len(text) line_count =len(text.splitlines())# ✨ 正确处理换行符! self.statusBar().showMessage(f"字数: {char_count} | 行数: {line_count}")# 🚀 启动程序if __name__ =="__main__": app = QApplication(sys.argv) window = SimplePad() window.show() sys.exit(app.exec())

Read more

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

【OpenClaw从入门到精通】第10篇:OpenClaw生产环境部署全攻略:性能优化+安全加固+监控运维(2026实测版)

摘要:本文聚焦OpenClaw从测试环境走向生产环境的核心痛点,围绕“性能优化、安全加固、监控运维”三大维度展开实操讲解。先明确生产环境硬件/系统选型标准,再通过硬件层资源管控、模型调度策略、缓存优化等手段提升响应速度(实测响应效率提升50%+);接着从网络、权限、数据三层构建安全防护体系,集成火山引擎安全方案拦截高危操作;最后落地TenacitOS可视化监控与Prometheus告警体系,配套完整故障排查清单和虚拟实战案例。全文所有配置、代码均经实测验证,兼顾新手入门实操性和进阶读者的生产级部署需求,帮助开发者真正实现OpenClaw从“能用”到“放心用”的跨越。 优质专栏欢迎订阅! 【DeepSeek深度应用】【Python高阶开发:AI自动化与数据工程实战】【YOLOv11工业级实战】 【机器视觉:C# + HALCON】【大模型微调实战:平民级微调技术全解】 【人工智能之深度学习】【AI 赋能:Python 人工智能应用实战】【数字孪生与仿真技术实战指南】 【AI工程化落地与YOLOv8/v9实战】【C#工业上位机高级应用:高并发通信+性能优化】 【Java生产级避坑指南:

By Ne0inhk
ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

ARM Linux 驱动开发篇--- Linux 并发与竞争实验(互斥体实现 LED 设备互斥访问)--- Ubuntu20.04互斥体实验

🎬 渡水无言:个人主页渡水无言 ❄专栏传送门: 《linux专栏》《嵌入式linux驱动开发》《linux系统移植专栏》 ❄专栏传送门: 《freertos专栏》《STM32 HAL库专栏》 ⭐️流水不争先,争的是滔滔不绝  📚博主简介:第二十届中国研究生电子设计竞赛全国二等奖 |国家奖学金 | 省级三好学生 | 省级优秀毕业生获得者 | ZEEKLOG新星杯TOP18 | 半导纵横专栏博主 | 211在读研究生 在这里主要分享自己学习的linux嵌入式领域知识;有分享错误或者不足的地方欢迎大佬指导,也欢迎各位大佬互相三连 目录 前言  一、实验基础说明 1.1、互斥体简介 1.2 本次实验设计思路 二、硬件原理分析(看过之前博客的可以忽略) 三、实验程序编写 3.1 互斥体 LED 驱动代码(mutex.c) 3.2.1、设备结构体定义(28-39

By Ne0inhk
Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

Flutter for OpenHarmony:swagger_dart_code_generator 接口代码自动化生成的救星(OpenAPI/Swagger) 深度解析与鸿蒙适配指南

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net 前言 后端工程师扔给你一个 Swagger (OpenAPI) 文档地址,你会怎么做? 1. 对着文档,手写 Dart Model 类(容易写错字段类型)。 2. 手写 Retrofit/Dio 的 API 接口定义(容易拼错 URL)。 3. 当后端修改了字段名,你对着报错修半天。 这是重复劳动的地狱。 swagger_dart_code_generator 可以将 Swagger (JSON/YAML) 文件直接转换为高质量的 Dart 代码,包括: * Model 类:支持 json_serializable,带 fromJson/

By Ne0inhk
Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

Linux 开发别再卡壳!makefile/git/gdb 全流程实操 + 作业解析,新手看完直接用----《Hello Linux!》(5)

文章目录 * 前言 * make/makefile * 文件的三个时间 * Linux第一个小程序-进度条 * 回车和换行 * 缓冲区 * 程序的代码展示 * git指令 * 关于gitee * Linux调试器-gdb使用 * 作业部分 前言 做 Linux 开发时,你是不是也遇到过这些 “卡脖子” 时刻?写 makefile 时,明明语法没错却报错,最后发现是依赖方法行没加 Tab;想提交代码到 gitee,记不清 git add/commit/push 的 “三板斧”,还得反复搜教程;用 gdb 调试程序,输了命令没反应,才想起编译时没加-g生成 debug 版本;甚至连写个进度条,都搞不懂\r和\n的区别,导致进度条乱跳…… 其实这些问题,

By Ne0inhk