QT学习笔记(二)
在 Qt 中,信号可以直接连接到另一个信号(Signal-to-Signal),这是一种非常实用的机制。当第一个信号被发射时,会自动触发第二个信号的发射,实现信号的 “转发” 或 “传递”。这种方式常用于解耦组件间的依赖,例如子窗口的信号通过主窗口转发或多个信号需要联动触发同一逻辑。假设场景:子窗口(ChildWidget)有一个按钮,点击后发射sendData(int)信号;主窗口(MainWi
1、信号连接信号
在 Qt 中,信号可以直接连接到另一个信号(Signal-to-Signal),这是一种非常实用的机制。当第一个信号被发射时,会自动触发第二个信号的发射,实现信号的 “转发” 或 “传递”。这种方式常用于解耦组件间的依赖,例如子窗口的信号通过主窗口转发或多个信号需要联动触发同一逻辑。
信号连接信号的语法与 “信号连接槽” 完全一致,只需将connect函数的第四个参数(接收者的成员)指定为另一个信号即可:
// 语法:信号A连接到信号B
connect(发送者A, &发送者A类::信号A,
发送者B, &发送者B类::信号B);
实战示例:子窗口信号通过主窗口转发
假设场景:子窗口(ChildWidget)有一个按钮,点击后发射sendData(int)信号;主窗口(MainWindow)需要将该信号转发为自己的forwardData(int)信号,最终由主窗口的槽处理。
// childwidget.h
#include <QWidget>
#include <QPushButton>
class ChildWidget : public QWidget {
Q_OBJECT
public:
explicit ChildWidget(QWidget *parent = nullptr) : QWidget(parent) {
QPushButton *btn = new QPushButton("发送数据", this);
// 点击按钮时发射信号sendData(随机数)
connect(btn, &QPushButton::clicked, this, [this](){
int data = qrand() % 100; // 生成0-99的随机数
emit sendData(data);
});
}
signals:
void sendData(int value); // 子窗口的信号
};
// mainwindow.h
#include <QMainWindow>
#include "childwidget.h"
#include <QDebug>
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) {
// 创建子窗口并添加到主窗口
ChildWidget *child = new ChildWidget(this);
setCentralWidget(child);
// 核心:将子窗口的sendData信号连接到主窗口的forwardData信号
connect(child, &ChildWidget::sendData,
this, &MainWindow::forwardData);
// 主窗口的forwardData信号连接到自己的槽函数处理
connect(this, &MainWindow::forwardData,
this, &MainWindow::handleData);
}
signals:
void forwardData(int value); // 主窗口的转发信号
private slots:
void handleData(int value) { // 处理转发后的数据
qDebug() << "主窗口处理数据:" << value;
}
};
处理逻辑:
1、点击子窗口的 “发送数据” 按钮 → 子窗口发射sendData(随机数)。
2、由于sendData连接到forwardData → 主窗口自动发射forwardData(随机数)。
3、forwardData连接到handleData槽 → 最终打印数据。
通过这种方式,子窗口无需知道主窗口的处理逻辑,主窗口也无需直接处理子窗口的信号,完全解耦。
2、Lambda表达式
在 C++(尤其是 Qt 开发)中,Lambda 表达式是一种匿名函数(没有名称的函数),自 C++11 起引入,常用于简化代码、定义临时回调逻辑(如 Qt 的信号槽连接)。它的核心优势是可以直接在需要函数的地方定义逻辑,无需单独声明函数,特别适合简短的功能实现。
Lambda 的完整语法结构如下:
[capture-list](parameters) mutable -> return-type {
// 函数体(逻辑实现)
}
[capture-list](捕获列表): 指定 Lambda 外部的变量如何被内部访问(核心特性),如[this]、[=]、[&]等。
(parameters)(参数列表): 与普通函数的参数列表一致,若无参数可省略(可写为()或直接省略)。
mutable(可选): 允许 Lambda 内部修改按值捕获的变量(默认不可修改)。
-> return-type(返回类型): 指定返回值类型,若函数体只有return语句且类型明确,可省略(由编译器自动推导)。
{…}(函数体): 具体的逻辑实现。
捕获列表决定了 Lambda 如何访问外部变量,是 Lambda 最灵活的特性,常见用法:
Lambda 最常用的场景是作为 Qt 信号的 “槽函数”,替代传统的public slots声明,使代码更紧凑。
2.1、基础示例:按钮点击事件
无需定义单独的槽函数,直接在connect中用 Lambda 处理逻辑:
#include <QPushButton>
#include <QDebug>
// 在某个类的成员函数中(如构造函数)
QPushButton *btn = new QPushButton("点击我", this);
connect(btn, &QPushButton::clicked, this, [=](){
qDebug() << "按钮被点击了!";
btn->setText("已点击"); // 因按值捕获[=],可访问btn(但修改指针指向无效,修改对象内容有效)
});
2.2、带参数的信号:处理信号传递的值
若信号有参数(如QSlider::valueChanged(int)),Lambda 的参数列表需匹配信号的参数:
#include <QSlider>
#include <QLabel>
QSlider *slider = new QSlider(Qt::Horizontal, this);
QLabel *label = new QLabel("0", this);
slider->setRange(0, 100);
// 滑块值变化时,用Lambda更新标签文本
connect(slider, &QSlider::valueChanged, this, [=](int value){
label->setText(QString::number(value)); // 接收信号的int参数,更新标签
});
2.3、处理信号重载:明确参数类型
当信号有重载(如QComboBox::currentIndexChanged有int和const QString&两个版本),Lambda 的参数列表可直接指定类型,避免歧义:
#include <QComboBox>
QComboBox *combo = new QComboBox(this);
combo->addItems({"A", "B", "C"});
// 连接"当前文本变化"的重载版本(参数为QString)
connect(combo, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),
this, [=](const QString &text){
qDebug() << "当前文本:" << text;
});
// 连接"当前索引变化"的重载版本(参数为int)
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, [=](int index){
qDebug() << "当前索引:" << index;
});
2.4、捕获this指针:访问类成员
在类的成员函数中,用[this]捕获当前对象指针,可直接访问类的成员变量 / 函数:
class MyWidget : public QWidget {
Q_OBJECT
private:
int count = 0; // 类成员变量
public:
MyWidget(QWidget *parent = nullptr) : QWidget(parent) {
QPushButton *btn = new QPushButton("计数", this);
connect(btn, &QPushButton::clicked, this, [this](){
count++; // 访问类成员变量
qDebug() << "计数:" << count;
updateUI(); // 调用类成员函数
});
}
private:
void updateUI() {
// 更新界面的逻辑
}
};
2.5、mutable的使用:
按值捕获的变量默认是const的,无法在 Lambda 内部修改。若需修改,需加mutable:
int x = 10;
auto func = [x]() mutable { // 允许修改按值捕获的x
x = 20;
qDebug() << "内部x:" << x; // 输出20
};
func();
qDebug() << "外部x:" << x; // 仍为10(按值捕获,不影响外部)
更多推荐
所有评论(0)