Prompt
[IMPORTANT: You are running as a scheduled cron job. DELIVERY: Your final response will be automatically delivered to the user — do NOT use send_message or try to deliver the output yourself. Just produce your report/output as your final response and the system handles the rest. SILENT: If there is genuinely nothing new to report, respond with exactly "[SILENT]" (nothing else) to suppress delivery. Never combine [SILENT] with content — either report your findings normally, or say [SILENT] and nothing more.]
[IMPORTANT: You are running as a scheduled cron job. DELIVERY: Your final response will be automatically delivered to the user — do NOT use send_message or try to deliver the output yourself. Just produce your report/output as your final response and the system handles the rest. SILENT: If there is genuinely nothing new to report, respond with exactly "[SILENT]" (nothing else) to suppress delivery. Never combine [SILENT] with content — either report your findings normally, or say [SILENT] and nothing more.]
你是一个Qt/C++启蒙教练,教学风格"通俗优先,严谨次之"。
首先读取进度文件:
`bash
cat /tmp/qt_teach_progress.txt 2>/dev/null || echo "0"
`
然后根据进度选择下一个知识点,输出一篇通俗易懂的Qt教学内容。
⚠️ 重要:你的回复将被直接发送到飞书(Feishu)聊天窗口。飞书支持 Markdown 格式,但有严格限制:
【飞书Markdown限制——必须遵守】
- 绝对不要使用 Markdown 表格(| | | 语法)——飞书检测到表格会回退到纯文本模式,导致所有Markdown格式失效
- 用列表(- 或 *)替代表格中的对比信息
- 总输出长度控制在6000字符以内
- 使用 ## 作为二级标题
- 使用 文字 作为粗体
- 使用
`cpp 和`包裹代码块 - 使用 - 或 * 作为列表项
【内容结构】
主题名称
一句话概括今天学什么。
为什么需要它?
(80-100字,说明这个知识解决了什么编程痛点)
人间烟火类比
(用一个生活场景彻底讲透核心思想,50-80字)
核心代码
`cpp
// 25-35行代码,带详细中文注释
`
深入理解
(150-200字,展开讲解底层原理、常见误区、最佳实践)
常见陷阱
(2-3个实际开发中最容易踩的坑,每个配一行代码)
关键提醒
(一句话点出最核心的记忆点)
课后小练习
(一道思考题或小题目)
【进度管理】
读取 /tmp/qt_teach_progress.txt 获取 NEXT_INDEX,每次递增。
每次输出完成后,用 write_file 更新进度文件。
【输出要求】
- 不要输出任何思考过程、分析过程或解释性文字
- 直接开始输出内容,不要写"让我先检查..."、"根据搜索结果..."之类的话
- 不要在输出中包含任何 Cron Job 元数据、Prompt 内容或 Response 标记
- 只输出教学内容本身,干净利落
- 绝对不要用表格!用列表对比!
Response
信号与槽:Qt 的事件总线
今天搞懂 Qt 最核心的机制——信号与槽,它是整个 Qt 框架的神经系统。
为什么需要它?
在传统的 C++ GUI 编程中,处理用户交互往往依赖回调函数、全局函数指针或者复杂的观察者模式,代码耦合度高且难以维护。Qt 通过信号与槽机制将事件发送者与接收者解耦,让对象之间的通信变得类型安全、简洁直观,彻底告别烦人的回调地狱。
人间烟火类比
信号与槽就像公司里的邮件抄送系统。你发一封邮件(触发信号),不需要知道谁在收,系统自动投递给所有订阅了这个邮箱的人(连接槽函数)。发件人和收件人互不干扰,想加收件人随时加,想换人发也随便换。
核心代码
`cpp
#include <QCoreApplication>
#include <QObject>
#include <QDebug>
// 自定义按钮类,继承自 QObject
class MyButton : public QObject {
Q_OBJECT // 宏:启用信号/槽机制,必须放在类开头
public:
explicit MyButton(const QString &name, QObject *parent = nullptr)
: QObject(parent), mName(name) {}
// 模拟点击操作
void simulateClick() {
qDebug() << mName << "被点击了!";
emit clicked(); // 发射信号,像发邮件一样广播出去
}
signals:
// 声明信号:返回void,无参数,可以有重载
void clicked();
private:
QString mName;
};
// 日志处理器类
class Logger : public QObject {
Q_OBJECT
public:
void onButtonClick() {
qDebug() << "[日志] 收到按钮点击事件!";
}
// 槽函数:普通的 public 成员函数,可以被信号连接
void onButtonClickVerbose(const QString &buttonName) {
qDebug() << "[详细日志]" << buttonName << "被点击!";
}
};
int main(int argc, char *argv[]) {
QCoreApplication app(argc, argv);
MyButton btn1("确认按钮");
MyButton btn2("取消按钮");
Logger logger;
// 连接信号到槽:btn1点击时触发logger.onButtonClick()
QObject::connect(&btn1, &MyButton::clicked, &logger, &Logger::onButtonClick);
// 连接信号到Lambda表达式(Qt5+推荐写法)
QObject::connect(&btn2, &MyButton::clicked, []() {
qDebug() << "[Lambda] 取消按钮被按下了!";
});
// 模拟点击
btn1.simulateClick();
btn2.simulateClick();
return 0;
}
// 注意:需要在 .pro 文件中加入 QT += core
// qmake 会自动生成 moc_*.cpp 文件处理信号槽
`
深入理解
信号与槽的本质是类型安全的回调机制。编译期,MOC(Meta-Object Compiler)会扫描带有 Q_OBJECT 宏的类,自动生成元对象代码,把信号和槽的索引映射表构建出来。运行时,QObject::connect() 将发送者的信号索引与接收者的槽函数指针关联起来,存入一个内部列表中。当 emit 被调用时,Qt 通过元对象系统查找所有连接的槽并依次调用。
Qt 提供了五种连接类型:DirectConnection(同步立即调用)、QueuedConnection(异步放入事件队列)、BlockingQueuedConnection(异步但阻塞发送方)、AutoConnection(默认值,同线程等效 Direct,跨线程等效 Queued)以及 UniqueConnection(防止重复连接)。理解连接类型对避免死锁和性能问题至关重要,尤其是跨线程场景中误用 DirectConnection 会导致灾难性后果。
常见陷阱
- 忘记 Q_OBJECT 宏:编译器不会报错,但运行时连接失败,静默失效
- 悬空指针:断开对象前未 disconnect,导致访问已销毁对象的槽函数
- lambda 捕获问题:
connect(sender, &Class::signal, this, this;中 this 可能先于信号源被销毁
关键提醒
信号是"宣告式"的广播,槽是"响应式"的订阅——发出去就不管了,这是解耦的艺术。课后小练习
尝试修改上面的代码,给 MyButton 增加一个带参数的信号 void clicked(const QString &text),并在 Lambda 中接收这个参数打印出来。思考:如果同一个信号连接了三个不同的槽,它们的执行顺序是怎样的?