QT——信号和槽机制

        信号和槽用于两个对象之间的通信,信号和槽机制是Qt的核心特征,也是Qt不同于其他开发框架的最突出的特征。

        信号和槽机制的特色和优越性:

            1. 信号和槽机制是类型安全的,相关联的信号和槽的参数必须匹配;

            2. 信号和槽是松耦合的,信号发送者不知道也不需要知道接受者的信息;

            3. 信号和槽可以使用任意类型的任意数量的参数。

        虽然信号和槽机制提供了高度的灵活性,但就其性能而言,还是慢于回调机制的。

    /*
    信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中做到有的放矢,
    避免产生一些错误。下面就介绍一下这方面的情况。
1.信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失,
    当然这种损失相对来说是比较小的,通过在一台i586-133的机器上测试是10微秒(运行Linux),
    可见这种机制所提供的简洁性、灵活性还是值得的。
    但如果我们要追求高效率的话,比如在实时系统中就要尽可能的少用这种机制。
2.信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能产生死循环。
    因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样信号。
    例如,在前面给出的例子中如果在mySlot()槽函数中加上语句emit mySignal()即可形成死循环。
3.如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。
4. 宏定义不能用在signal和slot的参数中。
    既然moc工具不扩展#define,因此,在signals和slots中携带参数的宏就不能正确地工作,如果不带参数是可以的。
    例如,下面的例子中将带有参数的宏SIGNEDNESS(a)作为信号的参数是不合语法的:
    */

        在GUI编程中,当改变了一个部件时,总希望其他部件也能了解到该变化。更一般来说,我们希望任何对象都可以和其他对象进行通信。

        当一个特殊的事情发生时便可以发射一个信号,比如按钮被单击;而槽就是一个函数,它在信号发射后被调用,来响应这个信号。

        在Qt的部件类中已经定义了一些信号和槽,但是更多的做法是子类化这个部件,然后添加自己的信号和槽来实现想要的功能。

        一个信号对应一个槽。其实,一个信号可以关联到多个槽上,多个信号也可以关联到同一个槽上,甚至,一个信号还可以关联到另一个信号上。如果存在多个槽与某个信号相关联,那么,当这个信号被发射时,这些槽将会一个接一个地执行,但是它们执行的顺序是随机的,无法指定它们的执行顺序。


一个简单的例子来进一步讲解信号和槽的相关知识,这个例子实现的效果是:在主界面中创建一个对话框,在这个对话框中可以输入数值,当按下确定按钮时关闭对话框并且将输入的数值通过信号发射出去,而在主界面中接收该信号并且显示数值。

  1. 子类mydialog.h中声明一个信号:

    signals:

        void dlgReturn(int);                  // 自定义的信号

    声明一个信号要使用signals关键字,在signals前面不能使用public、private和protected等限定符,因为只有定义该信号的类及其子类才可以发射该信号。而且信号只用声明,不需要也不能对它进行定义实现。还要注意,信号没有返回值,只能是void类型的。

  2. 在mydialog.ui的“确定”按钮clicked()槽函数中添加:

    void MyDialog::on_pushButton_clicked()   // 确定按钮

    {

       int value = ui->spinBox->value();    // 获取输入的数值

       emit  dlgReturn(value);               // 发射信号

       close();                             // 关闭对话框

    }

  3.  然后到widget.h文件中添加自定义槽的声明:

     private slots:

        void showValue(int value);

    声明一个槽需要使用slots关键字。一个槽可以是private、public或者protected类型的,槽也可以被声明为虚函数,这与普通的成员函数是一样的,也可以像调用一个普通函数一样来调用槽。槽的最大特点就是可以和信号关联。

  4. widget.cpp的构造函数中添加:

    MyDialog *dlg = new MyDialog(this);

    // 将对话框中的自定义信号与主界面中的自定义槽进行关联

    connect(dlg,SIGNAL(dlgReturn(int)),this,SLOT(showValue(int)));

    dlg->show();

  5. widget.cpp 中实现自定义槽函数:

    void Widget::showValue(int value)         // 自定义槽

    {

       ui->label->setText(tr("获取的值是:%1").arg(value));

    }

  6. 运行程序


connect()函数原型:

//connect()函数,这个函数的原型如下:
bool QObject::connect ( const QObject *sender, const char * signal, const QObject * receiver, const char * method,Qt::ConnectionType type = Qt::AutoConnection )
/*
它的第一个参数为发送信号的对象,例如这里的dlg;
第二个参数是要发送的信号,这里是SIGNAL(dlgReturn(int));
第三个参数是接收信号的对象,这里是this,表明是本部件,即Widget,当这个参数为this时,也可以将这个参数省略掉,
    因为connect()函数还有另外一个重载形式,该参数默认为this;
第四个参数是要执行的槽,这里是SLOT(showValue(int))。对于信号和槽,必须使用SIGNAL()和SLOT()宏,它们可以将其参数转化为const char* 类型。
connect()函数的返回值为bool类型,当关联成功时返回true。
还要注意,在调用这个函数时信号和槽的参数只能有类型,不能有变量,例如写成SLOT(showValue(int value))是不对的。
对于信号和槽的参数问题,基本原则是信号中的参数类型要和槽中的参数类型相对应,而且信号中的参数可以多于槽中的参数,但是不能反过来,如果信号中有多余的参数,那么它们将被忽略。
下面介绍一下connect()函数的最后一个参数,它表明了关联的方式,其默认值是Qt::AutoConnection,
这里还有其他几个选择,在编程中一般使用默认值,
例如这里,在MyDialog类中使用emit发射了信号之后,就会执行槽,只有等槽执行完了以后,才会执行emit语句后面的代码。
大家也可以将这个参数改为Qt::QueuedConnection,这样在执行完emit语句后便会立即执行其后面的代码,而不管槽是否已经执行。
当不再使用这个关联时,还可以使用disconnect()函数来断开关联。
*/


注意:

        需要继承自QObject或其子类;

        在类声明的最开始处添加Q_OBJECT宏;

        槽中的参数的类型要和信号的参数的类型相对应,且不能比信号的参数多;

        信号只用声明,没有定义,且返回值为void类型。

信号和槽的高级应用:

         有时我们希望获得信号发送者的信息,在Qt中提供了QObject::sender()函数来返回发送该信号的对象的指针。但是如果有多个信号关联到了同一个槽上,而在该槽中需要对每一个信号进行不同的处理,使用上面的方法就很麻烦了。对于这种情况,便可以使用QSignalMapper类。QSignalMapper可以被叫做信号映射器,它可以实现对多个相同部件的相同信号进行映射,为其添加字符串或者数值参数,然后再发射出去。


转载于:https://my.oschina.net/zengjs275/blog/544417

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值