IT评测·应用市场-qidao123.com

标题: QT信号与槽:实现方法、技术细节、高级用法和底层机制 [打印本页]

作者: 美食家大橙子    时间: 2025-3-14 17:53
标题: QT信号与槽:实现方法、技术细节、高级用法和底层机制
1. 基本概念

信号(signals):当对象的状态发生变化或发生特定事件时,自动触发的通知。比如PushButton常见的信号是clicked()信号。
槽:吸收信号并执行逻辑的成员函数。可定义在类的任何部分(public、private、protected)
连接:通过QObject::connect将信号与槽绑定。connect(sender, &Sender::signal, receiver, &Receiver::slot);
2. 四种方法实现

(1)右击控件 → 转到槽(自动天生槽函数)
Qt Creator 自动天生槽函数声明和实现,并在代码中创建连接。
  1. // 自动生成槽函数声明(头文件中)
  2. private slots:
  3.     void on_pushButton_close_clicked();
  4. // 自动生成槽函数实现(源文件中)
  5. void OnlineMusicWidget::on_pushButton_close_clicked()
  6. {
  7.     close();
  8. }
复制代码
(2)connect函数 + 宏(旧版本)
使用 SIGNAL() 和 SLOT() 宏定义信号和槽。通过字符串匹配信号和槽,运行时解析。
  
  1. connect(
  2.     ui->pushButton,
  3.     SIGNAL(clicked()),
  4.     this,
  5.     SLOT(handleButtonClick())
  6. );
  7. // 槽函数声明
  8. public slots:
  9.       void handleButtonClick();
复制代码
  1. connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandleLCDNumerTimeChangeFunc(qint64)));
  2. connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandlePositionChangeFunc(qint64)));
  3. connect(p_PlayerObject,SIGNAL(durationChanged(qint64)),this,SLOT(HandleProgressTimeChangeFunc(qint64)));
  4. // 槽函数声明
  5. private slots:
  6.     void HandleProgessTimeChangeFunc(qint64 dration);
  7.     void HandlePositionChangeFunc(qint64 position);
  8.     void HandleLCDNumberTimeChangeFunc(qint64 duration);
复制代码
(3)connect 函数 + 地址(新版本)
使用&类名::信号 和 &类名::槽直接引用函数地址。编译时静态绑定,类型安全。
  
  1. connect(
  2.     ui->pushButton,
  3.     &QPushButton::clicked,
  4.     this,
  5.     &MainWindow::handleButtonClick
  6. );
  7. // 槽函数声明
  8. public slots:
  9.     void handleButtonClick();
复制代码
  1. connect(
  2.     p_PlayerObject,             // 发送信号的对象(例如 QMediaPlayer 实例)
  3.     &QMediaPlayer::durationChanged, // 信号(当媒体时长变化时触发)
  4.     this,                       // 接收槽函数的对象(当前类的实例)
  5.     &MyClass::HandleProgressTimeChangeFunc // 槽函数(处理时长变化的函数)
  6. );
  7. connect(p_PlayerObject, &QMediaPlayer::durationChanged, this, &OnlineMusicWidget::HandleProgressTimeChangeFunc);
复制代码
 (4)Lambda 表达式(简化槽函数)
使用 Lambda 表达式直接处置惩罚信号逻辑。将槽函数更换为匿名函数,无需显式定义槽。
  1. // 自动生成槽函数声明(头文件中)
  2. private slots:
  3.     void on_pushButton_close_clicked();
  4. // 自动生成槽函数实现(源文件中)
  5. void OnlineMusicWidget::on_pushButton_close_clicked()
  6. {
  7.     close();
  8. }// 使用 Lambda 连接点击信号    connect(        pushButton_close,           // 发送信号的对象        &QPushButton::clicked,      // 信号        this,                       // 吸收者(当前窗口)        [this]() {                  // Lambda 表达式(槽函数)            close();                // 关闭当前窗口        }    );
复制代码
方法类型安全编译查抄灵活性适用场景转到槽是是低快速原型开辟connect + 宏否否中Qt 4 兼容或动态连接connect + 地址是是高新项目、类型安全要求高Lambda 表达式是是高简单逻辑、制止定义槽函数  3. 技术细节

(1)信号与槽的元对象系统:
moc(元对象编译器):

元方法(Meta-Method):

  1. const QMetaObject *meta = sender->metaObject();
  2. int signalIndex = meta->indexOfSignal("valueChanged(int)");
  3. int slotIndex = meta->indexOfSlot("handleValue(int)");
  4. QMetaObject::connect(sender, signalIndex, receiver, slotIndex);
复制代码
(2)信号的重载处置惩罚
强制类型转换解决重载歧义
  1. // 假设信号有重载:void valueChanged(int) 和 void valueChanged(QString)
  2. connect(
  3.     sender,
  4.     static_cast<void (SenderClass::*)(int)>(&SenderClass::valueChanged),
  5.     receiver,
  6.     &ReceiverClass::handleIntValue
  7. );
复制代码
(3)信号与槽的返回值

4. 高级用法

(1)信号与信号连接

  1. connect(
  2.     button, &QPushButton::clicked,
  3.     this, &MainWindow::startProcessingSignal
  4. );
复制代码
 (2)跨线程通讯(QueuedConnection)

  1. connect(
  2.     workerThread, &Worker::resultReady,
  3.     mainThread, &MainWindow::updateUI,
  4.     Qt::QueuedConnection
  5. );
复制代码
(4)Lambda 表达式进阶

  1. int threshold = 100;
  2. connect(
  3.     slider, &QSlider::valueChanged,
  4.     [threshold, this](int value) {
  5.         if (value > threshold) this->alert();
  6.     }
  7. );
复制代码

  1. connect(
  2.     spinBox, QOverload<int>::of(&QSpinBox::valueChanged),
  3.     [](int value) { qDebug() << "Value:" << value; }
  4. );
复制代码
4. 底层原理

(1)信号的本质

(2)槽的调用机制

(3)事件循环与信号槽

5. 实际案例

(1)动态界面更新
  1. // 根据数据变化动态更新多个 UI 控件
  2. connect(
  3.     dataModel, &DataModel::dataChanged,
  4.     this, [this](int index) {
  5.         updateChart(index);
  6.         updateTable(index);
  7.         logChange(index);
  8.     }
  9. );
复制代码
(2)异步任务链
  1. // 链式异步操作(下载 → 解析 → 显示)
  2. connect(
  3.     downloader, &Downloader::finished,
  4.     parser, &DataParser::parse,
  5.     Qt::QueuedConnection
  6. );
  7. connect(
  8.     parser, &DataParser::parsed,
  9.     this, &MainWindow::showResult,
  10.     Qt::QueuedConnection
  11. );
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4