Qt中的信号槽(上)

信号和槽的概念:

类似于一些其他的编程语言或者框架中的回调机制,信号和槽是Qt基于C++语法新增的特性,使用起来非常方便,可以完成不同对象之间的通信

信号槽的使用需要有以下两个条件:

(1)通信的对象必须继承自QObject类,QObject是Qt所有内置类型的基类

(2)类中要有Q_OBJECT宏

函数原型:

信号槽需要连接后才能触发,因此信号槽的核心是连接函数,连接函数是一个静态成员函数

QObject::connect(const QObject * sender,

const char * signal,

const QObject * receiver,

const char * method) [static]

参数1:发射者,发射者是一个对象,此对象发射信号函数,作为信号槽的触发条件

参数2:信号函数,参数一中的发射者发射出的信号函数,作为信号槽的触发条件,需要使用SIGNAL()包裹函数名称

参数3:接收者,接收者是一个对象,此对象执行槽函数,作为信号槽的执行结果

参数4:槽函数,参数3中接收者要执行的槽函数,作为信号槽的执行结果。需要使用SLOT()包裹函数名称

接收者绑定了发射者的信号函数,一旦发射者发射信号函数,接收者就执行槽函数

注意:

还有第五个参数,一般使用默认的。

(1)Qt::AutoConnection:默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型

(2)Qt::DirectConnection:槽函数会在信号发送的时候直接调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能造成崩溃

(3)Qt::QueuedConnection:槽函数在控制回到接收者所在的线程的事件循环时被调用,槽函数运行于信号接收者所在的线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个

(4)Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::Queued一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个

(5)Qt::UniqueConnection:这个flag可以通过按位与(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,在进行重复连接就会失败。也就是避免了重复连接

连接方式:

例子:

用槽函数实现:点击按钮,关闭窗口

(1)自带信号->自带槽

分析:先找因果关系的四个参数

参数1:发射者,按钮对象

参数2:信号函数,点击

参数3:接收者,窗口对象

参数4:槽函数,关闭

代码示例:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn;
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("关闭",this);
    btn->setGeometry(100,100,100,100);

    // 连接信号槽
    //  参数1:发射者,按钮对象
    //    参数2:信号函数,点击
    //    参数3:接收者,窗口对象
    //    参数4:槽函数,关闭
    connect(btn,SIGNAL(clicked()),this,SLOT(close()));
}

Dialog::~Dialog()
{
    delete btn;
}
(2)自带信号->自定义槽

在实际开发中,Qt不可能内置所有的函数,特别是槽函数,更好地情况是需要用户自定义一个槽函数来实现特定的功能,这种方式也是最常见的一种信号槽连接方式

需要注意的是,槽函数是一种特殊的成员函数,实现槽函数的方式与普通成员函数类似

代码示例:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>
#include <QDebug>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn;

private slots: // 私有槽函数
    // 声明自定义槽函数
    void mySlot();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    resize(400,400);
    btn = new QPushButton("向右下方移动",this);
    btn->setGeometry(100,100,100,100);

    // 连接信号槽
    //    参数1:按钮对象 btn
    //    参数2:clicked
    //    参数3:窗口对象 this
    //    参数4:自定义槽函数 mySlot
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
}

void Dialog::mySlot()
{
    // 先获得当前窗口的坐标
    int x = this->x();
    int y = this->y();
    // 增加后移动
    move(x+10,y+10);
    // 输出当前坐标
    qDebug() << x+10 << "," << y+10;
}

Dialog::~Dialog()
{
    delete btn;
}
(3)自定义信号->自定义槽

现在的思路需要有两个信号槽的连接,在自定义槽函数中要手动发射一个自定义信号函数,信号函数是一种非常特殊的函数,信号函数只有声明,没有定义;信号函数没有权限

代码示例:

dialog.h

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <QPushButton>

class Dialog : public QDialog
{
    Q_OBJECT

public:
    Dialog(QWidget *parent = 0);
    ~Dialog();

private:
    QPushButton *btn;

private slots:
    // 自定义槽函数
    void mySlot();

signals: // 信号函数没有权限
    // 自定义信号函数只需要声明就能使用
    void mySignal();
};

#endif // DIALOG_H

dialog.cpp

#include "dialog.h"

Dialog::Dialog(QWidget *parent)
    : QDialog(parent)
{
    btn = new QPushButton("关闭",this);
    btn->move(100,100);

    // 第一个信号槽的连接
    connect(btn,SIGNAL(clicked()),this,SLOT(mySlot()));
    // 第二个信号槽的连接
    connect(this,SIGNAL(mySignal()),this,SLOT(close()));
}

void Dialog::mySlot()
{
    // 发射自定义信号
    emit mySignal();
}

Dialog::~Dialog()
{
    delete btn;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值