Qt编程中的信号和槽机制

Qt编程中的信号和槽机制

在使用自定义类创建一个按钮之后,只能看到一个按钮的图形,但是使用鼠标点击并无任何反应,下面想要实现一个“点击按钮可以关闭窗口”的功能。

关闭窗口的功能可以被抽象为以下对象和操作,即:按钮,点击按钮,窗口,关闭窗口。在qt中使用connect实现这个过程。
connet(信号的发送者,发送的具体信号,信号的接受者,信号的处理(槽))
信号槽的一个优点:松散耦合,即信号的发送端和接收端本身是没有关联的,通过connect连接,将两端耦合在一起。

// myself button
MyPushButton *myBtn = new MyPushButton;
myBtn->setText("mybtn");
myBtn->setParent(this);
myBtn->move(10, 0);
myBtn->resize(200, 100);

// close the window
connect(myBtn, &QPushButton::clicked, this, &myWidget::close);
// 通过帮助文档查找按钮对应的信号 signals & slots

以上即 信号和槽 的简单功能演示。其中用到的信号和槽是父类中已经定义好的用来实现特定的功能,下面来实现自定义的信号和槽功能。过程为:跑完步,张三口渴拿起杯子喝水。新建一个类,在自动生成的类声明位置,可以看到其中包含放置自定义信号的位置,信号只需要声明,不需要实现,可以包含参数但不需要返回值。如下,信号就定义好了。

class Person : public QObject
{
    Q_OBJECT
public:
    explicit Person(QObject *parent = nullptr);
    
signals:
    void thirsty();
};

接下来是实现接收方的槽函数,早期版本槽函数必须写在类中的特定位置,5.4版本之后也可以将槽函数写在public中。槽函数既需要声明又需要实现,返回值为void,同样可以传入参数。

class Cup : public QObject
{
    Q_OBJECT
public:
    explicit Cup(QObject *parent = nullptr);

signals:

public slots:
    void drink();  // 还需到源文件中去定义
};

此时将信号和槽连接起来还不能看到效果,是因为信号未触发,只有信号触发后,与该信号连接的槽才能做出反应。

void Widget::overRun()
{
    emit zhangsan->thirsty();
}

信号发出后,与之相连的槽做出反应。

zhangsan = new Person(this);
beizi = new Cup(this);
connect(zhangsan, &Person::thirsty, beizi, &Cup::drink);
overRun();

信号和槽都可以传入参数,可以根据需要分别对其进行重载。注意,引用重载后需要利用函数指针明确指向具体函数。

// class Person
signals:
    void thirsty(QString WaterName);

// class Cup
public slots:
    void drink(QString WaterName);

// cup 定义
void Cup::drink(QString Watername)
{
    qDebug() << "drink water, " << Watername;
}

// widget 定义
void Widget::overRun()
{
    emit zhangsan->thirsty("Nongfu Water");
}

void (Person:: *zhangsanSignal)(QString) = &Person::thirsty;
void (Cup:: *beiziSlots)(QString) = &Cup::drink;
connect(zhangsan, zhangsanSignal, beizi, beiziSlots);
overRun();

输出结果为:drink water, "Nongfu Water",可以看到Nongfu Water被引号引起来了,想要去掉引号可以这样做:

qDebug() << "drink water, " << Watername.toUtf8().data();
// toUtf8()将QString转化为QByteArray,再使用data()将其转化为 char *

上面的实现中张三想要喝水的信号是调用函数触发的,下面想通过点击按钮的方式触发张三喝水的动作。

void (Person:: *zhangsanSignal)(QString) = &Person::thirsty;
void (Cup:: *beiziSlots)(QString) = &Cup::drink;
connect(zhangsan, zhangsanSignal, beizi, beiziSlots);

QPushButton *btn = new QPushButton("跑步结束", this);
btn->move(50, 50);
resize(300, 200);
connect(btn, &QPushButton::clicked, this, &Widget::overRun);

上面的实现中,相当于点击按钮后将信号传递给了widget下的槽函数overRun,也可以通过信号传递给信号的方式,点击按钮直接触发张三口渴的信号,如下:

void (Person:: *zhangsanSignal)(void) = &Person::thirsty;
void (Cup:: *beiziSlots)(void) = &Cup::drink;
connect(zhangsan, zhangsanSignal, beizi, beiziSlots);
connect(btn, &QPushButton::clicked, zhangsan, zhangsanSignal);

信号连接之后,也可以通过disconnect()断开连接,其参数与想要断开的连接中的参数相同,例如断开张三拿起杯子喝水的连接:

disconnect(zhangsan, zhangsanSignal, beizi, beiziSlots);

信号和槽要注意的几个点:
1、信号可以连接信号;
2、一个信号可以连接多个槽函数;
3、多个信号可以连接同一个槽函数;
4、信号和槽函数的参数需要一一对应;
5、在参数对应的前提下,信号的参数可以多于槽函数的参数个数。

补充:Qt4信号槽连接方式connect(zhangsan, SIGNAL(thirsty()), beizi, SLOT(drink()));,相对于更高版本,QT4连接参数直观,但编辑器不进行参数类型检测。因为QT4底层实现时相当于将thirsty()转化成字符串然后去搜索该函数,没有对字符串进行比较。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值