Qt信号与槽连接

信号与槽连接

qt5格式:

connect(pointer1, pointer2, pointer3, pointer4);

pointer1:指向发送信号的对象的指针

pointer2:发送信号的对象所对应的类的成员函数的指针

pointer3:接收信号的对象的指针

pointer4:接收信号的对象所对应对象的槽函数指针

其中pointer2,和pointer4都是函数指针,必须使用类名::成员函数名,并且pointer2和pointer4函数参数类型一致,pointer4会忽略pointer2传递的多余参数,pointer4可以是普通函数(无需public slots:修饰)。

总结下来就是:

  1. 信号:只需声明无需实现,且没有返回值;
  2. 槽函数:QT5类中任意成员函数,静态函数,全局函数,lambda表达式,槽函数可以有返回值,但只有在作为普通函数调用时才能接受,信号触发调用时无法接受;
  3. 信号与槽使用函数指针形式传入时格式必须是类名::成员函数名(信号或槽);
  4. 信号和槽的参数列表顺序必须一致;
  5. 信号和槽的参数个数可以不一致,但要满足信号的参数个数大于等于槽函数参数个数,槽函数会忽略信号传递的多余参数。

例如:

MainWidget.h文件:

class MainWidget : public QWidget
{
    Q_OBJECT
public:
    explicit MainWidget(QWidget *parent = 0);
    QPushButton * pushButton;
    SubWidget * subWidget;

signals:

public slots:
    void switchWinSlot();
};

MainWidget.cpp文件:

MainWidget::MainWidget(QWidget *parent) : QWidget(parent), pushButton(new QPushButton(this))
{
    pushButton->setText(QStringLiteral("切换至子窗口"));
    subWidget = new SubWidget;
    connect(pushButton, &QPushButton::clicked, this, &MainWidget::switchWinSlot);
    connect(subWidget, &SubWidget::switchWin, this, &MainWidget::switchWinSlot);
    subWidget->setWindowTitle("sub");
    this->setWindowTitle("parent");
    this->resize(400, 300);
    subWidget->resize(400, 300);
}

void MainWidget::switchWinSlot()
{
    this->setVisible(!this->isVisible());
    this->subWidget->setVisible(!subWidget->isVisible());
}


另外

  1. 一个信号可以连接多个槽,槽函数的执行顺序是随机的,无法控制
  2. 多个信号可以连接一个槽
  3. 一个信号可以连接另一个信号(这两个信号可以是不同对象的信号)这里对第三点举例 
  4. 信号和槽连接成功后,可以断开连接disconnect

subwidget.h文件:

class SubWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SubWidget(QWidget *parent = 0);
    QPushButton * pushButton;

signals:
    void switchWin();

public slots:
};

subwidget.cpp文件:

SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
    pushButton = new QPushButton(this);
    pushButton->setText(QStringLiteral("切换至父窗口"));
    connect(pushButton, &QPushButton::clicked, this, &SubWidget::switchWin);
}

此例子是子窗口产生clicked信号时会同时产生自定义的switchWin信号,用来实现主窗口与子窗口之间的切换

此外

信号和槽函数可以进行重载,利用Qt5格式连接重载的信号和槽时,应该使用函数指针变量对重载信号或槽进行区分

subwidget.h文件:

class SubWidget : public QWidget
{
    Q_OBJECT
public:
    explicit SubWidget(QWidget *parent = 0);
    QPushButton * pushButton;

signals:
    void switchWin();
    void switchWin(bool);
public slots:
};

subwidget.cpp文件:

SubWidget::SubWidget(QWidget *parent) : QWidget(parent)
{
    pushButton = new QPushButton(this);
    pushButton->setText(QStringLiteral("切换至父窗口"));
    void (SubWidget::* pfun)() = &SubWidget::switchWin;
    void (SubWidget::* pfun2)(bool) = &SubWidget::switchWin;
    connect(pushButton, &QPushButton::clicked, this, pfun);
    connect(pushButton, &QPushButton::clicked, this, pfun2);
}

上述函数指针涉及到类成员函数的函数指针,详见:

http://blog.csdn.net/xiaoyink/article/details/79439676

这是我们对SubClass的switchWin进行了重载,所以也要对mainwidget.cpp中connect连接switchWin信号的代码进行修改,这里我们用另一种方法,使用static_cast<>运算符对函数指针进行类型转换来区别switchWin的重载;

mainwidget.cpp修改如下:

#include "mainwidget.h"
#include <QPushButton>
#include "subwidget.h"

MainWidget::MainWidget(QWidget *parent) : QWidget(parent), pushButton(new QPushButton(this))
{
    pushButton->setText(QStringLiteral("切换至子窗口"));
    subWidget = new SubWidget;
    connect(pushButton, &QPushButton::clicked, this, &MainWidget::switchWinSlot);
    //connect(subWidget, &SubWidget::switchWin, this, &MainWidget::switchWinSlot);//修改之前
    connect(subWidget, static_cast<void(SubWidget::*)()>(&SubWidget::switchWin), this, &MainWidget::switchWinSlot);
    subWidget->setWindowTitle("sub");
    this->setWindowTitle("parent");
    this->resize(400, 300);
    subWidget->resize(400, 300);
}
void MainWidget::switchWinSlot()
{
    subWidget->setVisible(!subWidget->isVisible());
    this->setVisible(!this->isVisible());
}

上述涉及到的函数指针和重载函数的结合使用可以参考:

http://blog.csdn.net/xiaoyink/article/details/79441277

也可以利用Qt4中的信号与槽连接机制对重载进行区分,但不推荐使用,因为qt4使用宏定义会将函数名转化成字符串,所以并不会提供编译的错误检查,并且,SLOT()宏要求所有的槽函数必须使用xxx(public) slots:关键字进行修饰,qt4格式如下:

    connect(sender, SIGNAL(signal), receiver, SLOT(slot));

最后

connect函数还可以使用lambda表达式,在pro文件中加入CONFIG+=c++11,上述connect语句可以换成

    connect(pushButton, &QPushButton::clicked,
                [=](){
                    emit switchWin();
                });

或者

 connect(pushButton, &QPushButton::clicked,
                [this](){
                    emit this->switchWin();
                });

关于lambda表达式的用法详见:

http://blog.csdn.net/xiaoyink/article/details/79351350

补充

connect()函数可以自己设置第5个参数:

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, 
Qt::ConnectionType type = Qt::AutoConnection)

最后一个参数取值及其含义如下:

Qt::AutoConnection (默认)
Qt::DirectConnection
Qt::QueuedConnection
Qt::BlockingQueuedConnection

Qt::UniqueConnection

Qt::AutoConnection:如果信号发送者和接受者在同一个线程,则选用Qt::DirectConnection,如果不在同一个线程,则使用Qt::QueuedConnection做参数;

Qt::DirectConnection:信号发送后,槽函数立即执行,且会将槽函数拉倒信号发送者所在线程执行,所以,发送者和接收者不在同一个线程时,使用此参数要考虑好后果,除非槽函数应该是可重入的,一般禁用这种情况;

Qt::QueuedConnection:信号发送后立即返回,不等槽函数执行完毕,槽函数在接收者所在线程执行,按照接收者线程的正常事件循环队列执行;(The slot is invoked when control returns to the event loop of the receiver's thread.)

Qt::BlockingQueuedConnection:类似Qt::QueuedConnection,只是信号发送后,发送者所在线程阻塞,等待槽函数返回,当发送者和接受者在同一个线程时,应该禁用这种方式,因为他会导致线程死锁,另外如果接收信号的对象所在线程没有事件循环,也会导致发送信号对象所在线程死锁,因为发送的信号无法被事件循环处理,而发送信号的线程却在等待处理结果,所以死锁;

Qt::UniqueConnection:这个标识可以和其他任何标示联合使用(用按位或操作符),它保证一个信号和一个槽之间只能调用一次connect()函数,如果连接已经存在,则调用失败。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值