信号与槽的总结
信号与槽的总结
QT中的信号与Linux的信号对比
1)信号源
2)信号的类型
3)信号的处理方式
QT信号与Linux信号的深度对比分析
一、信号源对比
QT信号
-
用户定义信号
:由开发者通过
signals:
关键字在QObject派生类中显式声明
class MyObject : public QObject {Q_OBJECT signals:void mySignal(int param); };
-
框架内置信号:QT框架提供的信号(如QPushButton的clicked())
-
信号触发方式
:通过
emit
关键字显式触发
emit mySignal(42);
Linux系统信号
-
系统预定义信号:由操作系统内核预先定义(如SIGINT、SIGSEGV等)
-
硬件产生信号:如SIGSEGV(内存访问错误)、SIGFPE(算术异常)
-
进程间信号
:通过kill()系统调用发送
kill(pid, SIGTERM);
二、信号类型对比
QT信号类型特征
特性 | 说明 |
---|---|
类型安全 | 编译时检查参数类型匹配 |
带参数 | 可携带任意数量、类型的参数 |
面向对象 | 必须属于某个QObject派生类 |
同步/异步 | 默认队列连接(异步),可设置为直接连接(同步) |
Linux信号类型特征
特性 | 说明 |
---|---|
固定编号 | 标准信号编号1-31,实时信号34-64 |
无参数 | 仅信号编号,不能携带额外数据 |
进程级别 | 与特定线程/进程关联,非面向对象 |
同步触发 | 信号处理函数在信号产生时立即执行 |
常见Linux信号示例:
SIGINT (2):终端中断信号(Ctrl+C)
SIGKILL (9):强制终止信号
SIGSEGV (11):无效内存访问
SIGTERM (15):终止请求信号
三、处理方式对比
QT信号处理(信号-槽机制)
// 连接方式
QObject::connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);// 槽函数声明
public slots:void updateValue(int newValue);**处理特点**:
- 多线程安全:自动跨线程事件队列传递
- 连接类型:
- 直接连接(同步执行)
- 队列连接(异步,接收者线程事件循环处理)
- 自动连接(默认,根据线程关系自动选择)
- 内存管理:自动处理对象生命周期(可使用Qt::UniqueConnection)
Linux信号处理
// 信号处理函数注册
struct sigaction sa;
sa.sa_handler = handler;
sigaction(SIGINT, &sa, NULL);void handler(int sig) {// 信号处理逻辑
}
处理特点:
- 同步执行:中断当前执行流立即处理
- 限制严格:
- 信号处理函数中只能调用异步信号安全函数
- 不能使用malloc等非可重入函数
- 特殊处理:
- SIGKILL和SIGSTOP不能被捕获或忽略
- 某些信号会导致核心转储(如SIGSEGV)
四、关键差异总结
对比维度 | QT信号 | Linux信号 |
---|---|---|
抽象级别 | 高层次面向对象机制 | 低层次操作系统机制 |
参数传递 | 支持复杂参数传递 | 仅信号编号,无参数 |
线程处理 | 自动处理跨线程通信 | 需要显式处理线程掩码 |
可靠性 | 可靠,不会丢失 | 非实时信号可能丢失 |
处理时机 | 通过事件循环异步处理 | 立即中断当前执行流 |
调试支持 | 可通过QtCreator调试 | 需要gdb等系统级调试工具 |
五、实际应用场景
QT信号典型用例
- GUI事件处理(按钮点击、窗口关闭)
- 跨线程通信(工作线程到主线程通知)
- 模块间解耦(观察者模式实现)
Linux信号典型用例
- 进程控制(优雅终止服务进程)
- 异常处理(内存错误、算术异常捕获)
- 进程间简单通知(无需复杂数据传递)
六、高级主题
QT信号的高级特性
-
Lambda表达式连接:
connect(button, &QPushButton::clicked, [=](){qDebug() << "Button clicked"; });
-
信号转发:
connect(obj1, &ClassA::signalA, obj2, &ClassB::signalB);
-
信号连接管理:
disconnect()
断开连接
Linux信号的进阶处理
-
信号屏蔽:
sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); pthread_sigmask(SIG_BLOCK, &set, NULL);
-
实时信号处理:
union sigval value; value.sival_int = 42; sigqueue(pid, SIGRTMIN, value); // 可携带少量数据
-
替代方案:更复杂的进程通信建议使用socket、管道等机制
信号槽中connect函数的使用
connect (const QObject *sender, const char * signal ,const QObject * receiver , const char * method , Qt::ConnectionType type = Qt::AutoConnection )
参数说明:
• sender:信号的发送者;
• signal:发送的信号(信号函数);
• receiver:信号的接收者;
• method:接收信号的槽函数;
• type: ⽤于指定关联⽅式,默认的关联⽅式为 Qt::AutoConnection,通常不需要⼿动设定。
在控件的问题上我们需要查阅的问题
内置了哪些信号,信号是何时触发的
内置了哪些槽,槽的作用是什么
一、常见控件的内置信号
- 按钮类控件(QPushButton等)
主要内置信号:
clicked()
:按钮被鼠标点击或键盘激活时触发pressed()
:按钮被按下时立即触发released()
:按钮被释放时触发toggled(bool checked)
:可切换按钮状态改变时触发
// 示例:连接按钮点击信号
connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::onButtonClicked);
- 文本输入类控件(QLineEdit, QTextEdit)
主要内置信号:
textChanged(const QString &text)
:文本内容改变时触发textEdited(const QString &text)
:用户编辑文本时触发returnPressed()
:按下回车键时触发editingFinished()
:编辑完成(失去焦点)时触发
// 示例:实时响应文本变化
connect(ui->lineEdit, &QLineEdit::textChanged,[this](const QString &text){qDebug() << "Current text:" << text;});
- 选择类控件(QComboBox, QCheckBox, QRadioButton)
主要内置信号:
currentIndexChanged(int index)
:当前选项改变时触发currentTextChanged(const QString &text)
:当前文本改变时触发stateChanged(int state)
:复选框/单选按钮状态改变时触发
// 示例:响应下拉框选择变化
connect(ui->comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),[](int index){qDebug() << "Selected index:" << index;});
二、信号触发时机详解
- 用户交互触发
- 鼠标事件:点击、双击、悬停等
- 键盘事件:按键按下、释放、输入等
- 触摸事件:触摸屏交互
- 状态变化触发
- 值改变:如滑块位置、进度条值等
- 焦点变化:控件获得/失去焦点
- 可见性变化:显示/隐藏状态改变
- 系统事件触发
- 定时器超时:QTimer的timeout()信号
- 网络响应:QNetworkReply的finished()信号
- 文件系统变化:QFileSystemWatcher的fileChanged()信号
三、常见控件的内置槽函数
- 基础功能槽
槽函数 | 作用 | 适用控件 |
---|---|---|
setText(const QString &) | 设置控件文本 | QLabel, QLineEdit等 |
clear() | 清空内容 | QLineEdit, QTextEdit等 |
setEnabled(bool) | 启用/禁用控件 | 所有QWidget派生类 |
show() /hide() | 显示/隐藏控件 | 所有QWidget派生类 |
// 示例:使用内置槽
connect(ui->actionClear, &QAction::triggered,ui->textEdit, &QTextEdit::clear);
- 状态控制槽
槽函数 | 作用 | 适用控件 |
---|---|---|
setChecked(bool) | 设置选中状态 | QCheckBox, QRadioButton |
setCurrentIndex(int) | 设置当前选项 | QComboBox, QTabWidget |
setValue(int) | 设置数值 | QProgressBar, QSlider |
// 示例:控制进度条
connect(ui->startButton, &QPushButton::clicked,[this](){ui->progressBar->setValue(0);});
四、槽函数的作用与分类
- 数据操作槽
- 数据获取:如
text()
、value()
等 - 数据设置:如
setText()
、setValue()
等 - 数据清除:如
clear()
、reset()
等
- 状态控制槽
- 启用/禁用控制:
setEnabled()
、setDisabled()
- 可见性控制:
show()
、hide()
、setVisible()
- 状态切换:
setChecked()
、toggle()
- 视图操作槽
- 滚动控制:
scrollToTop()
、scrollToBottom()
- 缩放控制:
zoomIn()
、zoomOut()
- 选择控制:
selectAll()
、deselect()
五、信号与槽的高级应用
- 自动连接命名槽
QT支持特定命名格式的槽函数自动连接:
// 声明
private slots:void on_pushButton_clicked();// 实现
void MainWindow::on_pushButton_clicked() {// 无需显式connect,自动关联名为"pushButton"的按钮点击信号
}
- 信号与槽的连接类型
// 五种连接类型
Qt::AutoConnection // 自动选择(默认)
Qt::DirectConnection // 同步直接调用
Qt::QueuedConnection // 异步队列调用
Qt::BlockingQueuedConnection // 阻塞式队列调用
Qt::UniqueConnection // 唯一连接(防止重复连接)
- Lambda表达式作为槽
connect(ui->pushButton, &QPushButton::clicked, [this](){// 可以直接访问类成员ui->label->setText("Button clicked at " + QTime::currentTime().toString());
});
六、最佳实践建议
- 信号-槽连接规范:
- 优先使用新式语法(
&Sender::signal
形式) - 避免在构造函数中连接尚未完全初始化的对象
- 优先使用新式语法(
- 资源管理:
- 使用
QPointer
管理可能被删除的对象 - 及时断开不再需要的连接(
disconnect
)
- 使用
- 线程安全:
- 跨线程连接使用
QueuedConnection
- 避免在不同线程间直接操作GUI控件
- 跨线程连接使用
- 性能优化:
- 高频信号考虑节流(throttling)或防抖(debouncing)
- 大量连接时考虑使用
QSignalMapper
或lambda统一处理
自定义槽函数
本质:自定义的一个普通的成员函数
可以让QTCreator自动生成
自定义信号
本质:成员函数
函数的定义是QT自己生成的,作为程序员只需要写函数声明即可
signals:自定义信号的关键字
emit:完成信号的发射(emit可以省略)
信号和槽也可以带参数
发射信号的时候,把参数传给对应的参数
信号的参数和槽的参数一致
1)类型匹配
2)个数,信号的参数要多于槽的参数
信号槽存在的意义:解耦合
代码要达到的要求:高内聚,低耦合
具体含义为:对程序影响很小,写代码的时候,某个代码的功能被集中在一起