信号与槽基本介绍
信号与槽(Signal & Slots)是Qt框架的核心机制,用于实现对象间的松耦合通信。它取代了传统的回调函数,提供更灵活、安全的方式处理时间响应。
基本概念
信号(Signal)
- 由对象在特定事件发生时发出(emit),如按钮点击、数据更新等。
- 声明在类的
signals:
区域,无需实现(由Qt的元对象系统自动生成)。 - 示例:按钮的
clicked()
信号。
槽(Slot)
- 普通的成员函数,用于响应信号,执行具体逻辑。
- 声明为
public slots:
、private slots:
等,或直接使用Q_SLOTS
宏(Qt5后支持普通函数作为槽)。 - 示例:关闭窗口的
close()
槽。
连接(Connection)
- 通过
QObject::connnect()
建立信号与槽的绑定关系。 - 支持多对多连接(一个信号可以出发多个槽,一个槽也可响应多个信号)。
特点
- 松耦合:信号发出者无需知道谁接手,槽也无需知道信号来源。
- 类型安全:参数类型和数量必须兼容(Qt5新语法支持编译时检查)。
- 跨线程通信:通过
Qt::QueuedConnection
实现线程间安全调用。 - 灵活连接:支持运行时动态连接或断开(
connect
/disconnect
)。
使用步骤
声明信号与槽
class MyWidget : public QWidget {Q_OBJECT // 必须包含,启用元对象特性
public:explicit MyWidget(QWidget *parent = nullptr);signals:void mySignal(int value); // 声明信号public slots:void mySlot(int value); // 声明槽函数
};
实现槽函数
void MyWidget::mySlot(int value) {qDebug() << "Received value:" << value;
}
连接信号与槽
- Qt5新语法(推荐,类型安全):
QObject::connect(sender, &SenderClass::signalName, receiver, &ReceiverClass::slotName);
示例:
QPushButton *button = new QPushButton("Click me");
connect(button, &QPushButton::clicked, this, &MyWidget::close);
- Qt4旧语法(兼容性保留):
connect(sender, SIGNAL(signalName(参数)), receiver, SLOT(slotName(参数)));
示例场景:点击按钮改变文本
// 窗口类定义
class MainWindow : public QMainWindow {Q_OBJECT
public:MainWindow();private slots:void updateLabel(); // 槽函数private:QLabel *label;QPushButton *button;
};// 实现
MainWindow::MainWindow() {label = new QLabel("Hello");button = new QPushButton("Change Text");// 连接按钮点击信号到槽connect(button, &QPushButton::clicked, this, &MainWindow::updateLabel);QVBoxLayout *layout = new QVBoxLayout;layout->addWidget(label);layout->addWidget(button);setCentralWidget(new QWidget);centralWidget()->setLayout(layout);
}void MainWindow::updateLabel() {label->setText("Text Changed!");
}
常见问题与技巧
连接失败的可能原因:
- 忘记添加
Q_OBJECT
宏。 - 信号/槽参数不匹配。
- 对象未正确初始化或已被销毁。
自动连接:
在Qt Designer中命名控件为on_控件名_信号
(如on_button_clicked()
),无需手动connect
。
Lambda表达式:
Qt5支持在连接时使用Lambda,简化代码:
connect(button, &QPushButton::clicked, [=]() {label->setText("Lambda Slot");
});
在上述代码中[=]
虽然是值传递方式,但是label是指针类型,使用[=]
会捕获指针本身(内存地址副本),所以可以通过->
操作符访问成员函数。
连接类型
通过第五个参数指定,如Qt ::QueuedConnection
(异步)、Qt::DirectConnection
(同步)。