问题的提出
对于一个图形界面来说,图形界面变成那个不仅需要运行时的高效性,还需要在C++对象模型的基础上添加了一些特性,形成了自己的对象模型,比如信号和槽,就是一个强大的无缝对象通信机制——信号和槽。
而connect函数就是连接信号和槽的最为关键的一点,下面将通过一个具体的工程来实现,举例如下:
Connect工程效果、
整体效果
点击PushButton后的效果
点击Child Dialog后的效果
Connect工程的头文件
#ifndef FATHERDIALOG_H
#define FATHERDIALOG_H
#include <QDialog>
namespace Ui {
class FatherDialog;
}
class FatherDialog : public QDialog
{
Q_OBJECT
public:
explicit FatherDialog(QWidget *parent = 0);
~FatherDialog();
private slots:
void on_pushButton_clicked();
void showChildDialog();
void on_childB_clicked();
void on_childB_clicked(bool checked);
private:
Ui::FatherDialog *ui;
};
#endif // FATHERDIALOG_H
Connect工程头文件的具体实现方法
#include "fatherdialog.h"
#include "ui_fatherdialog.h"
#include <QMessageBox>
FatherDialog::FatherDialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::FatherDialog)
{
ui->setupUi(this);
QObject::connect(ui->childB,
&QPushButton::clicked,
this,
&FatherDialog::showChildDialog);
}
FatherDialog::~FatherDialog()
{
delete ui;
}
void FatherDialog::on_pushButton_clicked()
{
QMessageBox::information(this,"提示","<font size='26'>请告诉我为什么</font>",QMessageBox::Ok);
}
void FatherDialog::showChildDialog()
{
QDialog * d= new QDialog(this);
d->show();
}
Connect工程的主函数
#include "fatherdialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FatherDialog w;
w.show();
return a.exec();
}
重要部分是信号和槽关联的部分,下面进行分析
槽和信号的关联使用的是QObject类的connect()函数,该函数的原型如下:
bool QObject::connect (const QObject * sender, const char * signal, const QObject * receiver, const char * slot) [static]
信号
当对象改变其状态时,信号就由该对象发射 (emit) 出去,而且对象只负责发送信号,它不知道另一端是谁在接收这个信号。这样就做到了真正的信息封装,能确保对象被当作一个真正的软件组件来使用。
信号只需要在头文件中进行声明,不需要在cpp中实现。放在Qt自定义关键字signals下,在此之前一定要加上Q_OBJECT宏。当对象改变其状态时,信号就由该对象发射 (emit) 出去,而且对象只负责发送信号,它不知道另一端是谁在接收这个信号。这样就做到了真正的信息封装,能确保对象被当作一个真正的软件组件来使用。在编程中,一般使用的是控件内部定义好的信号。如:QTreeWidget类下的 Signals,也可以自定义信号,并通过emit在代码中发射信号。
关联信号和槽(connect)
之前connect()函数的调用方式为
QObject::connect(ui->childB,
&QPushButton::clicked,
this,
&FatherDialog::showChildDialog);
注意
在connect函数中信号函数和槽函数若有参数,只能写出参数类型,而不能也将变量名写出;否则,连接会失败!
一个信号可以连接多个槽当信号发射时,会以不确定的顺序一个接一个的调用各个槽。
多个信号可以连接同一个槽即无论是哪一个信号被发射,都会调用这个槽。
信号直接可以相互连接发射第一个信号时,也会发射第二个信号。
断开信号和槽(disconnect)
当信号和槽没有必要继续保持连接时,可以通过调用disconnect来断开它们。
bool QObject::disconnect (const QObject * sender, const char * signal, const Object * receiver, const char * slot) [static]
(1)断开与某个对象相关联的任何对象。
disconnect(sender, 0, 0, 0) ;
//或者
sender->disconnect();
(2)断开与某个特定信号的任何关联。
disconnect(sender, SIGNAL(signal()), 0, 0);
//或者
sender->disconnect(SIGNAL(signal()));
(3)断开两个对象之间的关联。
disconnect(sender, 0, receiver, 0);
//或者
sender->disconnect(receiver);
应该注意的问题
信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样信号。例如 , 在前面给出的例子中如果在 mySlot() 槽函数中加上语句 emit mySignal() 即可形成死循环。
如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。
宏定义不能用在 signal 和 slot 的参数中。
信号和槽的参数个数与类型必须一致。