首页 > 其他分享 >【Qt 快速入门(三)】- Qt信号和槽

【Qt 快速入门(三)】- Qt信号和槽

时间:2024-06-11 08:59:34浏览次数:16  
标签:MyObject Qt mySignal QObject 信号 连接 入门

目录

Qt 快速入门(三)- Qt信号和槽

Qt信号和槽详解

Qt信号和槽机制是Qt框架中最为重要和核心的特性之一。它提供了一种在对象之间进行通信的方式,使得编写响应用户交互、事件处理等代码变得简洁而高效。信号和槽机制超越了传统的回调函数模式,提供了更强的类型安全和灵活性。

信号和槽的基本概念

信号

信号(Signal)是由对象发出的,用于通知其他对象某些事件已经发生。信号不包含任何处理代码,只是一个声明,表示某种事件的发生。

槽(Slot)是一个普通的成员函数,可以连接到一个或多个信号上。当信号发出时,与之连接的槽函数会被调用。槽可以有参数,与信号的参数相对应。

连接

信号和槽之间的连接是通过connect函数来实现的。当一个信号发出时,所有与之连接的槽函数都会被自动调用。这种机制允许多个信号连接到一个槽,也允许一个信号连接到多个槽。

信号和槽的声明与定义

在Qt中,信号和槽通常在类中声明,并且需要在类声明中使用signals和slots关键字标识。下面是一个简单的示例,演示如何在Qt中声明和定义信号与槽。

#include <QObject>
#include <QDebug>

class MyObject : public QObject {
    Q_OBJECT

public:
    explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}

signals:
    void mySignal(int value);

public slots:
    void mySlot(int value) {
        qDebug() << "Slot called with value:" << value;
    }
};

在上面的示例中,mySignal是一个信号,mySlot是一个槽。Q_OBJECT宏必须出现在类定义的开头,以启用Qt的元对象系统(Meta-Object System)。

连接信号和槽

信号和槽的连接使用QObject::connect函数。可以在类的构造函数中进行连接,也可以在程序的其他部分进行连接。以下是连接信号和槽的示例:

MyObject obj1;
MyObject obj2;

QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot);

// 触发信号
emit obj1.mySignal(42);

在上面的代码中,当obj1对象发出mySignal信号时,obj2对象的mySlot槽函数会被调用,并且传递42作为参数。

信号和槽的高级特性

自动参数匹配

信号和槽机制支持自动参数匹配。槽函数的参数数量可以少于信号的参数数量,只要参数类型匹配即可。多余的参数会被忽略。例如:

class MyObject : public QObject {
    Q_OBJECT

public:
    explicit MyObject(QObject *parent = nullptr) : QObject(parent) {}

signals:
    void mySignal(int value, const QString &text);

public slots:
    void mySlot(int value) {
        qDebug() << "Slot called with value:" << value;
    }
};

在这个示例中,即使信号mySignal有两个参数,也可以连接到只接受一个参数的槽mySlot。

MyObject obj1;
MyObject obj2;

QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySlot);

// 触发信号
emit obj1.mySignal(42, "Hello");
信号与信号连接

Qt允许信号之间的连接。当一个信号发出时,连接到它的另一个信号也会被发出。这对于实现复杂的事件传播机制非常有用。

MyObject obj1;
MyObject obj2;

QObject::connect(&obj1, &MyObject::mySignal, &obj2, &MyObject::mySignal);
QObject::connect(&obj2, &MyObject::mySignal, &obj2, &MyObject::mySlot);

// 触发信号
emit obj1.mySignal(42);

在这个示例中,当obj1发出mySignal信号时,obj2也会发出mySignal信号,然后obj2的mySlot槽函数会被调用。

lambda 表达式作为槽

从Qt 5开始,可以使用lambda表达式作为槽。这种方式非常方便,特别是在处理简单的信号和槽连接时。

MyObject obj;

QObject::connect(&obj, &MyObject::mySignal, [](int value) {
    qDebug() << "Lambda called with value:" << value;
});

// 触发信号
emit obj.mySignal(42);

在这个示例中,lambda表达式充当了槽,打印信号传递的值。

自定义信号和槽

除了Qt预定义的信号和槽,开发者还可以定义自己的信号和槽。这使得Qt信号和槽机制非常灵活,可以适应各种应用需求。

class CustomWidget : public QWidget {
    Q_OBJECT

public:
    CustomWidget(QWidget *parent = nullptr) : QWidget(parent) {
        connect(this, &CustomWidget::customSignal, this, &CustomWidget::customSlot);
    }

signals:
    void customSignal(int value);

public slots:
    void customSlot(int value) {
        qDebug() << "Custom slot called with value:" << value;
    }

    void emitSignal() {
        emit customSignal(99);
    }
};

在这个示例中,CustomWidget定义了一个自定义信号customSignal和一个自定义槽customSlot。在构造函数中,信号和槽进行了连接,当emitSignal函数被调用时,customSignal信号会被发出,customSlot槽会被调用。

信号和槽的线程支持

Qt的信号和槽机制天然支持多线程编程。信号和槽可以跨线程连接,使得线程间通信变得简单而高效。

跨线程连接

当信号和槽位于不同的线程中时,Qt会自动选择合适的连接方式:

  • 直接连接:如果信号和槽位于同一线程,槽会在发出信号的线程中立即被调用。
  • 队列连接:如果信号和槽位于不同的线程,槽会被放入目标线程的事件队列,并在目标线程的事件循环中执行。

下面是一个跨线程信号和槽连接的示例:

class Worker : public QObject {
    Q_OBJECT

public slots:
    void doWork(int value) {
        qDebug() << "Worker thread ID:" << QThread::currentThreadId();
        qDebug() << "Processing value:" << value;
    }
};

class Controller : public QObject {
    Q_OBJECT

public:
    Controller() {
        workerThread = new QThread(this);
        worker = new Worker();
        worker->moveToThread(workerThread);

        connect(this, &Controller::startWork, worker, &Worker::doWork);
        connect(workerThread, &QThread::finished, worker, &QObject::deleteLater);

        workerThread->start();
    }

    ~Controller() {
        workerThread->quit();
        workerThread->wait();
    }

signals:
    void startWork(int value);

private:
    QThread *workerThread;
    Worker *worker;
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    Controller controller;

    qDebug() << "Main thread ID:" << QThread::currentThreadId();
    emit controller.startWork(42);

    return app.exec();
}

在这个示例中,Controller类启动了一个工作线程,并将Worker对象移动到该线程。信号startWork和槽doWork之间的连接是跨线程的,当startWork信号发出时,doWork槽会在工作线程中执行。

信号和槽的生命周期管理

在Qt中,信号和槽连接的生命周期通常由QObject的父子关系管理。当一个QObject对象被销毁时,所有与之相关的信号和槽连接都会自动断开,避免了悬挂指针的问题。

自动断开连接

在以下示例中,当某个QObject对象被销毁时,相关的信号和槽连接会自动断开:

class Sender : public QObject {
    Q_OBJECT

signals:
    void mySignal(int value);
};

class Receiver : public QObject {
    Q_OBJECT

public slots:
    void mySlot(int value) {
        qDebug() << "Slot called with value:" << value;
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);

    Sender *sender = new Sender();
    Receiver *receiver = new Receiver();

    QObject::connect(sender, &Sender::mySignal, receiver, &Receiver::mySlot);

    emit sender->mySignal(42);

    delete receiver;  // 自动断开连接

    emit sender->mySignal(99);  // 不会调用槽函数,因为连接已经断开

    return app.exec();
}

在这个示例中,当receiver对象被删除时,与之相关的信号和槽连接会自动断开,避免了信号发出时访问无效内存的情况。

总结

Qt的信号和槽机制提供了一种强大而灵活的对象通信方式,使得开发者能够轻松地实现事件驱动的编程模型。通过信号和槽,开发者可以在对象之间建立松耦合的通信关系,编写高效、可维护的代码。本文详细介绍了信号和槽的基本概念、声明与定义、连接方法、线程支持以及生命周期管理,帮助开发者全面理解和掌握这一重要特性。

通过深入理解Qt信号和槽机制,开发者可以更加高效地构建复杂的Qt应用程序,并充分利用Qt框架的强大功能。在实际开发中,灵活运用信号和槽机制,可以极大地提高代码的可维护性和扩展性,满足各种应用需求。

标签:MyObject,Qt,mySignal,QObject,信号,连接,入门
From: https://blog.csdn.net/qq_38641481/article/details/139586518

相关文章

  • 802.11协议入门 1:信道接入机制
    目录1.序言2.CSMA/CD机制3.CSMA/CA机制3.1总体说明3.2基础概念说明3.3详细工作机制3.4BEB机制说明4.CSMA/CD与CSMA/CA差异1.序言    一晃从事通信领域已经十几年了,最近想把这些年来学到的一些知识整理并分享出来,也是自己一个查漏补缺的过程。本......
  • SDL3 入门(1):Hello, SDL3!
    在本系列中我们使用WindowsTerminal+Powershell组合作为我们在Windows系统下的终端工具,Windows11自带该环境。你也可以使用任意自己喜欢的终端环境代替,或使用鼠标执行等价的操作。源码准备我们使用git管理我们的项目,所以首先我们创建一个名为"hello_sdl3"的目录并......
  • kettle从入门到精通 第六十七课 ETL之kettle 再谈kettle阻塞,阻塞多个分支的多个步骤
    场景:ETL沟通交流群内有小伙伴反馈,如何多个分支处理完毕之后记录下同步结果呢?或者是调用后续步骤、存储过程、三方接口等。解决:使用步骤Blockingstep进行阻塞处理即可。 1、 如下流程图中利用Blockingstep步骤同时阻塞【模拟表输出1】和【模拟表输出2】两个步骤,只有当两个步......
  • IO进程线程(十二)进程间通信 共享内存 信号灯集
    文章目录一、共享内存sharedmemory(shm)(一)特点(二)相关API1.创建共享内存2.映射共享内存到当前的进程空间3.取消地址映射4.共享内存控制(三)使用示例(四)属性二、信号灯集---控制进程间同步(一)特点(二)相关API1.创建一个信号灯集2.信号灯集控制函数3.信号灯集的操作函......
  • QT工具uic、moc、rcc
    QT中的moc、uic、rcc在学习QT的过程中接触到了moc、uic、rcc这几个名词moc(Meta-ObjectCompiler),元对象编译器,用于处理QT拓展的C++语法uic(UserInterfaceCompiler),用户界面编译器,将根据.ui文件生成相应的.h文件,例如根据mainwindow.ui生成ui_mainwindow.hrcc(ResourceComp......
  • python入门基础知识(条件控制)
     本文内容来自菜鸟教程Python基础教程|菜鸟教程(runoob.com) 本人负责概括总结代码实现。以此达到快速复习目的。Python3条件控制Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块。可以通过下图来简单了解条件语句的执行过程:......
  • QT鼠标拖拽方式
    创建按钮,然后添加图片因为按钮是直接继承了ui类的,所以在ui界面直接把按钮进行拖拽就好给按钮添加上图片QPixmap和image的区别:QPixmap:QPixmap主要用于在屏幕上显示图像,通常用于GUI界面中的图像显示。QPixmap优化了对显示设备的访问,因此在显示图像时具有更好的性能。QPi......
  • QT 图片从屏幕桌面拖进窗口
    设置在Widget构造写接受拖拽事件函数这样才能使用后面的函数重写鼠标拖拽函数都是继承的widget的函数实现内部方法Drag部分://URLs是统一资源定位符(UniformResourceLocators)的复数形式。在计算机术语中,URLs用来标识和定位互联网上的资源,如网页、图片、视频等。它由若......
  • 2024最新最全【大模型技术AGI】入门到精通,看完这一篇就够了!
    学习大模型(例如GPT-3、BERT等)需要一定的数学和编程基础,以及对人工智能、机器学习、自然语言处理等领域的了解。以下是一个学习大模型的基本路线:基础知识储备:数学基础:掌握线性代数、概率论与数理统计、微积分等数学知识。编程基础:熟悉至少一种编程语言,如Python,因为大多......
  • 2024 年 Web 安全最详细学习路线指南,从入门到入职(含书籍、工具包)【建议收藏】
    第一个方向:安全研发你可以把网络安全理解成电商行业、教育行业等其他行业一样,每个行业都有自己的软件研发,网络安全作为一个行业也不例外,不同的是这个行业的研发就是开发与网络安全业务相关的软件。既然如此,那其他行业通用的岗位在安全行业也是存在的,前端、后端、大数据分......