【Qt秘籍】[009]-自定义槽函数/信号

自定义槽函数

在Qt中自定义槽函数是一个直接的过程,槽函数本质上是类的一个成员函数,它可以响应信号。所谓的自定义槽函数,实际上操作过程和定义普通的成员函数相似。以下是如何在Qt中定义一个自定义槽函数的步骤:

步骤 1: 定义槽函数

  1. 选择位置 : 槽函数通常定义在类的声明部分。在Qt 5及以上版本中,虽然不是强制要求,但传统上槽函数会放置在public slots:区域下。如果希望保持代码的清晰度和一致性,这样做是个好习惯。
cpp 复制代码
class MyClass : public QWidget {
    Q_OBJECT // 必须包含,以便使用信号和槽机制

public:
    MyClass(QWidget *parent = nullptr);
    ~MyClass();

public slots: // 槽函数区域
    void myCustomSlot(); // 自定义槽函数声明
};

步骤 2: 实现槽函数

接下来,在类的实现文件(.cpp)中为槽函数提供具体的实现。

cpp 复制代码
void MyClass::myCustomSlot() {
    qDebug() << "自定义槽函数被调用了!";
    // 在这里可以添加代码
}

步骤 3: 连接信号到槽

为了让槽函数响应特定的信号,你需要使用QObject::connect()函数来建立信号和槽之间的连接。

cpp 复制代码
MyClass myObject;
QPushButton button("点击我", &myObject);

// 连接按钮的clicked()信号到自定义槽函数
connect(&button, &QPushButton::clicked, &myObject, &MyClass::myCustomSlot);

在这个例子中,当按钮被点击时,myCustomSlot槽函数就会被调用。

注意事项:

  • 确保你的类包含Q_OBJECT宏,这是使用信号和槽机制的前提。
  • Qt 5开始支持lambda表达式作为槽函数,这为编写更简洁的代码提供了可能。
  • 如果你的槽函数不需要访问类的成员或不需要作为对象的成员存在,也可以声明为全局函数或静态成员函数。
  • 使用新式连接语法(如上述示例所示),它提供了类型安全和更好的编译时检查。

图形化界面

实际上,Qt的图形化界面让你能更加轻松的自定义槽函数。

步骤:

1.当你使用图形化界面直接拖拽一个pushbutton,右键点击可以发现可以直接 "转到槽..."

2.直接点击 clicked() ==> OK

3.Qt Creator 直接生成好了函数定义和声明,因此我们可以直接在此函数内部编写代码即可。

cpp 复制代码
//widget.h

private slots:
    void on_pushButton_clicked();

//widget.cpp

void Widget::on_pushButton_clicked()
{
    //在此处补充你的代码
}

如下图笔者给出的示例代码,当点击new按钮会使得左上角文字替换

问题:

为什么"转到槽..."(Go To Slot...)能在没有添加connect的情况下,将组件和函数关联起来?

回答:

"转到槽函数"(Go To Slot)是Qt Creator集成开发环境(IDE)提供的一项便捷功能,它允许开发者通过图形界面快速创建槽函数并自动关联到特定组件的信号上,而无需手动编写connect()代码行。这一自动化过程基于Qt的元对象系统(Meta-Object System)和Qt Creator对UI文件(如.ui文件)的处理机制。

当你在Qt Designer中右键点击一个控件并选择"转到槽..."(Go To Slot...),IDE会自动执行以下操作:

  1. 生成槽函数 : 如果你选择了一个预定义的信号(比如按钮的clicked()信号),Qt Creator会检查你的类是否已经有一个与之匹配的槽函数(命名规则通常是on_控件对象名_信号名())。如果没有,IDE会提示你创建这样一个槽函数,并自动生成相应的函数声明和定义。

  2. 自动连接 : 对于遵循特定命名约定 的槽函数,Qt Creator和moc(Meta-Object Compiler)会在编译时自动处理信号与槽的连接。这意味着,如果你按照约定命名了槽函数,即使你在代码中没有显式看到connect调用,信号和槽也会在运行时正确地关联起来。

  3. UI文件处理 : 当UI文件被编译为对应的C++代码(通常通过uic工具),这些自动关联的信息会被嵌入到生成的代码中,从而确保信号和槽在应用程序运行时能够正确交互。

因此,虽然表面上看起来没有手动添加connect()调用,但实际上是在IDE和编译流程中隐式完成了信号与槽的连接工作,确保了组件和函数能够正确关联。

自定义信号

在Qt中自定义信号涉及以下几个简单步骤:

步骤 1: 声明信号

  1. 定义信号 : 在类的声明中,你需要在signals:区域声明你的自定义信号。信号通常返回类型为void,并且不需要实现(即没有函数体)。
cpp 复制代码
class MyClass : public QObject {
    Q_OBJECT // 必须包含,以便使用信号和槽机制

public:
    MyClass(QObject *parent = nullptr);

signals: // 信号区域
    void customSignal(int value); // 自定义信号声明,参数可以根据需要设定
};

步骤 2: 发射信号

在类的实现中,你可以使用emit关键字来触发(发射)信号。通常,这会在某个特定条件满足或者事件发生时执行。

cpp 复制代码
MyClass::MyClass(QObject *parent) : QObject(parent) {
    // 在适当的位置发射信号,例如初始化完成后或者某个事件响应时
    emit customSignal(42); 
}

或者在类的其他成员函数内部根据需要发射信号:

cpp 复制代码
void MyClass::someFunction() {
    // 根据逻辑判断发射信号
    if (someCondition) {
        emit customSignal(getSomeValue());
    }
}

注意事项:

  • 确保类定义中包含了Q_OBJECT宏,这是使用信号和槽机制的基础。
  • 信号可以有任意数量和类型的参数,但不能有默认值,且返回类型必须是void。
  • 信号的命名通常以"signal"结尾,尽管这不是强制性的,但这样的命名约定有助于代码的可读性。
  • 发射信号是线程安全的,即使在非主线程中也可以安全地发射信号。

通过以上步骤,你就成功地在Qt中自定义并使用了一个信号。记得连接这个信号到相应的槽函数以完成对象间的通信。

相关推荐
小羊没烦恼!5 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读5 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
这个DBA有点耶5 天前
MVCC深入:Read View、版本链与快照读——InnoDB并发控制的内核
数据库·mysql·架构
DBA_G5 天前
从地面到云霄:GBase数据库在民航三大场景的落地实践
数据库
自由能燃气设备5 天前
商用全预混低氮冷凝锅炉免费方案vs付费方案对比+选型避坑指南
大数据·数据库·人工智能
C语言小火车5 天前
C/C++ 为什么需要编译器?
开发语言·c++
科创致远5 天前
科创致远 ESOP 系统核心效能与实战价值展示
大数据·数据库·人工智能·精益工程
霍霍的袁5 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超5 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int5 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++