欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt信号与槽连接

程序员文章站 2024-01-02 13:51:52
...

信号与槽连接

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()函数,如果连接已经存在,则调用失败。

上一篇:

下一篇: