QT-信号与槽用法实例与注意事项及五个连接方式详解

2023-05-16

1.基本用法
2.slots的函数用法
3.slots的lambda表达式
4.断开连接到对象信号的所有Object
5.断开连接到特定信号的所有Object
6.断开特定接收者
7.connect函数的第5参数Qt::ConnectionType
8.QObject::connect: Cannot queue arguments of type 'XXX'
9.QTimer的 singleShot
环境:
QT版本:5.6.2
VS版本:VS2013
系统版本:windows 7 64bit

前言
Qt 信号槽一直以来都是QT的核心之一。但是,大家真的对信号的槽非常了解吗?下面介绍的一些内容,你可能并不知道。

1.基本用法
QLabel *label = new QLabel;
QLineEdit *lineEdit = new QLineEdit;
QObject::connect(lineEdit, &QLineEdit::textChanged,label,  &QLabel::setText);

2.slots的函数用法
函数原型:

QMetaObject::Connection QObject::connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)

使用:

void someFunction();

QPushButton *button = new QPushButton;
QObject::connect(button, &QPushButton::clicked, someFunction);

3.slots的lambda表达式
QByteArray page = ...;
QTcpSocket *socket = new QTcpSocket;
socket->connectToHost("qt-project.org", 80);
QObject::connect(socket, &QTcpSocket::connected, [=] () {socket->write("GET " + page + "\r\n");});

4.断开连接到对象信号的所有Object
disconnect(myObject, 0, 0, 0);

等同于

myObject->disconnect();

5.断开连接到特定信号的所有Object
    disconnect(myObject, SIGNAL(mySignal()), 0, 0);

等同于

myObject->disconnect(SIGNAL(mySignal()));

6.断开特定接收者
disconnect(myObject, 0, myReceiver, 0);

等同于

myObject->disconnect(myReceiver);

7.connect函数的第5参数Qt::ConnectionType
参数    值    说明
Qt::AutoConnection    0    (默认)如果接收者位于发出信号的线程中,则使用Qt :: DirectConnection。 否则,使用Qt :: QueuedConnection。 连接类型在发出信号时确定
Qt::DirectConnection    1    发出信号时立即调用插槽。 插槽在信号线程中执行。相当于槽函数直接执行,执行完之后,才继续执行信号的后续内容
Qt::QueuedConnection    2    槽函数在控制回到接收者所在线程的事件循环时被调用。 槽函数在接收者的线程中执行。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用
Qt::BlockingQueuedConnection    3    与Qt :: QueuedConnection相同,除了信号线程阻塞直到槽返回。 如果接收者与信号位于同一线程中,则不得使用此连接,否则程序将会死锁
Qt::UniqueConnection    0x80    这是一个可以使用按位OR与上述任何一种连接类型组合的标志。 当设置Qt :: UniqueConnection时,如果连接已经存在,QObject :: connect()将失败(即,如果相同的信号已连接到同一对对象的相同插槽)。 这个标志是在Qt 4.6中引入的
这里需要注意的是一般我们都是采用默认参数Qt::AutoConnection。但是,需要注意有时可能会出现问题。
例如,我们要在登录成功后关闭当前界面。实现如下:

void login()
{
...
//验证完毕,返回登录成功信号
emit loginSuccess();
this->hide();
}

如果此时我们采用Qt::AutoConnection,并且信号与槽位于同一线程,那么QT会自动为我们选择为Qt::DirectConnection方式。也就是必须等待信号对应的槽函数执行完,才能执行hide操作。这是如果槽函数是一个耗时操作,那么就会出现无法hide的情况,这种情况下,我们需要手动设置Qt::QueuedConnection或者将hide函数在emit之前执行。

总结一下就是emit函数之后的内容的执行顺序与信号与槽的连接方式有关。如果需要立即执行emit之后的函数,就需要设置为Qt::QueuedConnection,如果要立即执行槽函数,就需要设置为Qt::DirectConnection。

8.QObject::connect: Cannot queue arguments of type ‘XXX’
出现这个错误是由于对于Qt::QueuedConnection连接,参数必须是Qt的元对象系统已知的类型,因为Qt需要复制参数以将它们存储在幕后的事件中。
在建立连接之前,请调用qRegisterMetaType()注册数据类型。

9.QTimer的 singleShot
函数原型:

[static] void QTimer::singleShot(int msec, const QObject *receiver, const char *member)

QTimer::singleShot(100,this, &A::function());

QTimer::singleShot(100,[=]{qDebug() << "time out"; });

/*********************************************************************

DisConnect:

bool QObject::disconnect(const QObject * sender, const char * signal, const QObject * receiver, const char *method) [static]

1. Disconnect everything connected to an object's signals:

取消某个对像的所有的信号连接:

disconnect(myObject,0,0,0);

equivalent to the non-static overloaded function

等价于:

myObject->disconnect();

2. Disconnect everything connected to a specific signal:

取消某个信号与它对应槽的所有连接:

disconnect(myObject, SIGNAL(mySignal()),0,0);

equivalent to the non-static overloaded function

等价于:

myObject->disconnect(SIGNAL(mySignal()));

3. Disconnect a specific receiver:

断开某个接收对象的连接:

disconnect(myObject,0, myReceiver,0);

equivalent to the non-static overloaded function

等价于:

myObject->disconnect(myReceiver);

/************************************

Qt信号的处理 (connect和disconnect和blockSignals的使用方法)

信号槽机制是Qt的非常重要的机制,本文不剖析信号槽机制的原理,只讲信号的主要使用方法。

信号:当某个事件发生后,比如按钮检测到自己被点击了一下,按钮会发出一个信号,这种发出是没有目的的,类似广播。

1. 信号连接槽  connect函数
connect函数最常用的一般形式:

connect(sender, signal, receiver, slot);
2. 解除信号和连接到信号的槽的连接 disconnect函数
disconect函数的原型如下:

bool QObject::disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *method)
一般有四种用法:

2.1  解除myObject对象的所有信号连接,调用后myObject对象发出的所有信号都得不到响应。

    disconnect(myObject, 0, 0, 0);
//等同于
    myObject->disconnect();
2.2  解除myObject对象的mySignal信号的所有连接,调用后myObject对象发出的mySignal信号得不到响应。

    disconnect(myObject, SIGNAL(mySignal()), 0, 0);
//等同于
    myObject->disconnect(SIGNAL(mySignal()));
2.3  解除myObject对象与myReceiver对象的信号连接,调用后myObject对象发出的所有信号得不到myReceiver对象的响应。

    disconnect(myObject, 0, myReceiver, 0);
//等同于
    myObject->disconnect(myReceiver);
2.4  解除myObject对象的mySignal信号与myReceiver对象的mySlot槽的连接,调用后myObject对象发出的mySignal信号得不到myReceiver对象的mySlot槽的响应。

    disconnect(myObject, SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));
//等同于
    myObject->disconnect(SIGNAL(mySignal(), myReceiver, SLOT(mySlot())));
ps:上述4种用法中,0是通配符,它表示任一信号、任一接收对象、任一槽。

3. 阻塞信号  blockSignals函数
blockSignals的函数原型如下:

bool QObject::blockSignals(bool block)
用法:

//object发出的信号被阻塞,系统不会调用任何连接到object的处理。
object->blockSignals(true);
 
//解除信号阻塞
object->blockSignals(false);
4.案例
//widget.h

#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    Widget(QWidget *parent = 0);
    ~Widget(){}
};
 
#endif // WIDGET_H
//widget.cpp

#include "widget.h"
 
#include <QPushButton>
#include <QGridLayout>
#include <QDebug>
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    /* 创建控件 */
    QPushButton *btnClick      = new QPushButton("click me", this);
    QPushButton *btnBlock      = new QPushButton("block", this);
    QPushButton *btnUnblock    = new QPushButton("unblock", this);
    QPushButton *btnDisconnect = new QPushButton("disconnect", this);
 
    QGridLayout *pLayout = new QGridLayout();
    pLayout->addWidget(btnClick, 0, 0);
    pLayout->addWidget(btnBlock, 0, 1);
    pLayout->addWidget(btnUnblock, 0, 2);
    pLayout->addWidget(btnDisconnect, 0, 3);
    this->setLayout(pLayout);
 
    /* 信号槽 */
    connect(btnClick, &QPushButton::clicked, this, [=]()
    {
        qDebug() << "点击按钮";
    });
 
    connect(btnBlock, &QPushButton::clicked, this, [=]()
    {
        btnClick->blockSignals(true);
        btnBlock->setEnabled(false);
        btnUnblock->setEnabled(true);
    });
 
    connect(btnUnblock, &QPushButton::clicked, this, [=]()
    {
        btnClick->blockSignals(false);
        btnBlock->setEnabled(true);
        btnUnblock->setEnabled(false);
    });
 
    connect(btnDisconnect, &QPushButton::clicked, this, [=]()
    {
        disconnect(btnClick, &QPushButton::clicked, this, 0);
    });
 
}
//main.c

#include "widget.h"
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
 
    return a.exec();
}
结果:

1.按下"click me"按钮,窗口接收到"click me"按钮发出的clicked信号,打印"点击按钮"。

2.然后再按下"block",再次按下"click me"按钮,没有打印"点击按钮"。这是因为 "click me"按钮发出的信号被阻塞了,没有得到响应。

3.然后再按下"unblock"按钮,再次按下"click me"按钮,打印"点击按钮"。这是因为解除了"click me"按钮的信号阻塞。

4.最后按下"disconnect"按钮,此时按下"click me"按钮没有反应。这是因为解除了本窗口与"click me"按钮的clicked信号的连接。 
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QT-信号与槽用法实例与注意事项及五个连接方式详解 的相关文章

随机推荐

  • QtCreator修改项目构建目录

    使用QtCreator编译Qt项目时 xff0c 如有需求修改编译过程文件 xff08 即Makefile o exe等文件 xff09 存放目录 xff0c 简单在工具 gt 选项 gt 构建和运行中修改Default build dir
  • QT中删除信号于槽的连接

    如果是在UI里建立的 xff0c 那就在下面这个函数里删除连接槽函数的对应行 void MainForm qt static metacall QObject o QMetaObject Call c int id void a if c
  • C++位操作中按位置0、置1、取反操作

    一 指定的某一位数置1 宏 define setbit x y x 61 1 lt lt y 二 指定的某一位数置0 宏 define clrbit x y x amp 61 1 lt lt y 三 指定的某一位数取反 宏 define r
  • LED恒流驱动IC汇总

    这几天在找LED恒流驱动芯片 xff0c 无意间在LED网论坛上发现这个帖子 xff0c 分享给大家 xff01 LED恒流IC芯片大盘点 韩国LDT LD1016 16位最大90mA LED屏幕 护栏灯管恒流驱动IC LD1048 48位
  • qt C++中指针自动释放内存及程序中的内存操作、管理

    程序加载到内存后代码存储到代码区 xff0c 并将全局变量 静态变量初始化到全局 静态内存区 xff0c 然后会分配2M左右的栈内存区用于存储局部变量 xff0c 并在运行时根据需要可以在堆内存区 空闲内存区及硬盘的虚拟内存区 申请空间 程
  • sqlite数据库文件提示损坏修复方法

    第1章 说明 1 1 下载SQLite Tools 1 2 运行 2 注意 xff1a 为了方便 xff0c 可把要修复的数据库文件直接放到sqlite3 exe路径下然后运行sqlite3 exe就不用输入具体路径了 sqlite3 ex
  • 常用的dos网络命令总结

    一 ping 主要是测试本机TCP IP协议配置正确性与当前网络现状 ping命令的基本使用格式是 xff1a ping IP地址 主机名 域名 t a n count l size t xff1a 连续对IP地址 主机名 域名执行Ping
  • C#中隐藏窗体并执行窗体逻辑的方法

    c 隐藏窗体方方法 this WindowState 61 FormWindowState Minimized this ShowInTaskbar 61 false base SetVisibleCore true 示例如下 Task F
  • qt中xe运行缺少组件,Qt-c++桌面编程报错:qt.qpa.plugin: Could not find the Qt platform plugin “windows“ in ““,最终解决方案

    报以上错误是因为编译出来的exe程序缺少一些qt的组件 xff0c 需要补全放到exe同级目录下即可 编译库 xff1a Qt GUI xff0c qt5 12 1 软件类型 xff1a Qt application xff0c qt桌面软
  • C#中异步窗体的调用的几种方法

    在子线程里创建的窗体在其他线程里调用的异步调用操作方法 xff1a 1 在另一个线程里找到异步窗体句柄 xff0c 向其传送自定义消息ID 异步窗体的消息循环需要重写加入相应自定义方法 2 找到异步线程里的窗体 xff0c 用该窗体类型直接
  • C++中UDP通讯详解

    C 43 43 Socket编程及TCP UDP通信代码实现 一 简介 Socket编程的目的是使网络的进程进行通信 xff0c 基于TCP IP协议簇 xff0c 通过三元组 xff08 ip地址 协议 端口 xff09 标志进程 xff
  • UDP中connect()和send()函数详解

    UDP也是有connect方法的 xff0c 下面为大家讲解一下这个connect方法 我们知道UDP是无连接的 xff0c 它可以给多个IP发送数据包 xff0c 包括广播地址或者多播通信的实现 xff0c 而这些是TCP IP无法实现的
  • UDP传输报文大小详解

    UDP的传输方式 xff1a 面向报文 面向报文的传输方式决定了UDP的数据发送方式是一份一份的 xff0c 也就是应用层交给UDP多长的报文 xff0c UDP就照样发送 xff0c 即一次发送一个报文 那么UDP的报文大小由哪些影响因素
  • UDP通信概念问题

    1 UDP 多个线程 通过同一个端口接收和发送数据 xff0c 是双向不收影响的还是在时序上错开的 xff1f 如题 xff0c 比如接收到了不同地址的的UDP数据 xff0c 现在通过多个线程从同一个端口回发数据 那么数据的收发都是同一个
  • KMeans算法-手写数字图像识别

    数据聚类是无监督学习的主流应用 最经典并易用的聚类模型 xff0c 是K means算法 该算法要求我们预设聚类的个数 xff0c 然后不断更新聚类中心 xff1b 经过几轮迭代后 xff0c 让所有数据点到其所属聚类中心距离的平方和趋于稳
  • C++中创建二维数组的几种方法

    一 用new申请内存空间 int dp 61 new int n 动态申请二维数组nxm for int i 61 0 i lt n 43 43 i dp i 61 new int m 二 用malloc申请内存空间 1 int len 6
  • QT中使用C++ socket通信,socket通信原理三次握手和四次握手详解、客户端与服务端实例详解

    对TCP IP UDP Socket编程这些词你不会很陌生吧 xff1f 随着网络技术的发展 xff0c 这些词充斥着我们的耳朵 那么我想问 xff1a 1 什么是TCP IP UDP xff1f 2 Socket在哪里呢 xff1f 3
  • Qt-笔记(以太网与Q_OBJECT相关)

    1 qt中引用socket需要在 pro文件中加入LIBS 43 61 lpthread libwsock32 libws2 32 xff0c 头文件中再包含 lt WinSock2 h gt 2 使用信号槽的类必须继承自Q OBJECT
  • qt中使用全局变量和静态变量示例(静态变量在.h文件中声明后必须在cpp文件中定义否则编译报错)

    静态变量可以在各个页面之前使用 先定义一个用于存放静态变量的类 例如datavar 在datavar h中添加如下代码 ifndef DATAVAR H define DATAVAR H include lt QObject gt clas
  • QT-信号与槽用法实例与注意事项及五个连接方式详解

    1 基本用法 2 slots的函数用法 3 slots的lambda表达式 4 断开连接到对象信号的所有Object 5 断开连接到特定信号的所有Object 6 断开特定接收者 7 connect函数的第5参数Qt ConnectionT