风中落叶

顾毅的博客

Qt异体图标

Qt备忘录之三:slots与signals初探

| 这篇文章还没有评论

slots和signals不是c++的关键字,刚接触真是雾煞煞。所以先不管slots和signals是什么碗糕,用起来再说!

slots和signals的一般用法:

还是看《 GUI Programming with 4 2nd Edition》书上的例子。

age.pro:

QT += widgets

TEMPLATE      = app
SOURCES       = age.cpp

age.cpp:

#include <QApplication>
#include <QHBoxLayout>
#include <QSlider>
#include <QSpinBox>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    QWidget *window = new QWidget;//新建一个Widget实例
    window->setWindowTitle("Enter Your Age");//设置window对象的标题

    QSpinBox *spinBox = new QSpinBox;//新建一个QSpinBox实例
    QSlider *slider = new QSlider(Qt::Horizontal);//新建一个水平放置的QSlider实例
    spinBox->setRange(0, 130);//设置上述两个对象的值范围
    slider->setRange(0, 130);

    QObject::connect(spinBox, SIGNAL(valueChanged(int)),
                     slider, SLOT(setValue(int)));
//将spinBox的valueChanged(int)信号与slider的槽setValue(int)建立连接

    QObject::connect(slider, SIGNAL(valueChanged(int)),
                     spinBox, SLOT(setValue(int)));
//将slider的valueChanged(int)信号与spinBox的槽setValue(int)建立连接

 spinBox->setValue(35);

 QHBoxLayout *layout = new QHBoxLayout;//新建一个布局对象
 layout->addWidget(spinBox);//将上述的spinBox和slider作为layout的成员加入layout中
 layout->addWidget(slider);
 window->setLayout(layout);//将layout作为window的成员加入window中

 window->show();//将window呈现

 return app.exec();
}

其他的东西都是c++的标准写法,一般都能看懂,关键是以下两句:

    QObject::connect(spinBox, SIGNAL(valueChanged(int)),
                     slider, SLOT(setValue(int)));

    QObject::connect(slider, SIGNAL(valueChanged(int)),
                     spinBox, SLOT(setValue(int)));

Qt Creator中,按住Ctrl再点具体的函数明或者参数名,会跳转到其声明。用这个方法查看第18行中的valueChange(int),跳转到QSpinBox类的头文件qspinbox.h中:

Q_SIGNALS:
    void valueChanged(int);
    void valueChanged(const QString &);

可见,valueChanged是QSpinBox类的一个“Q_SIGNALS”权限的成员。再去看Q_SIGNALS的定义,其实是一个宏。相应的,Q_SLOTS也是一个宏。暂时不去深究这些宏在编译的时候起什么作用,从效果上来看,就是当spinBox对象发出valueChanged(int)信号时,slider的setValue(int)槽起了作用。这就实现了两个对象之间的通信。

connect函数原型分析

根据qobject.h和Qt官方的帮助文档,connect函数有以下几种重载:

QMetaObject::Connection	connect(const QObject * sender, const char * signal, const QObject * receiver, const char * method, Qt::ConnectionType type = Qt::AutoConnection)
QMetaObject::Connection	connect(const QObject * sender, const QMetaMethod & signal, const QObject * receiver, const QMetaMethod & method, Qt::ConnectionType type = Qt::AutoConnection)
QMetaObject::Connection	connect(const QObject * sender, PointerToMemberFunction signal, const QObject * receiver, PointerToMemberFunction method, Qt::ConnectionType type = Qt::AutoConnection)
QMetaObject::Connection	connect(const QObject * sender, PointerToMemberFunction signal, Functor functor)
QMetaObject::Connection	connect(const QObject * sender, PointerToMemberFunction signal, const QObject * context, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)

上面的示例使用的是第一个重载方法。其中,sender是信号端的对象指针,signal是信号名,receiver是槽端的对象指针,method是槽名。语句中的SIGNAL()和SLOT()的定义,则可以从qobjectdef.h中找到。

qobjectdef.h

#ifndef QT_NO_META_MACROS
#ifndef QT_NO_DEBUG
# define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   qFlagLocation("0"#a QLOCATION)
# endif
# define SLOT(a)     qFlagLocation("1"#a QLOCATION)
# define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)
#else
# ifndef QT_NO_KEYWORDS
#  define METHOD(a)   "0"#a
# endif
# define SLOT(a)     "1"#a
# define SIGNAL(a)   "2"#a
#endif

这其实是两个宏,作用分别是提取出信号或者槽名,并加上标注以区分。如果定义2个QString,用于接收SIGNAL(valueChanged(int))和SLOT(setValue(int)),在调试模式可以看到SIGNAl()和SLOT()的结果如下:

SIGNAL()宏

SLOT()宏

这边涉及到Qt的元对象编译机制,后面如果有机会会深入研究。第二种和第三种重载,其实本质上和第一种一样,只不过现在是根据QMetaMethod对象和PointerToMemberFunction对象来指定signal和slot。

第五种,是将sender对象的signal与context对象的函数functor做连接。根据Qt的官方文档,这个functor还可以是lambda表达式。第四种是第五种把当前对象作为Receiver的特殊形式,相当于:

QMetaObject::Connection	connect(const QObject * sender, PointerToMemberFunction signal, this, Functor functor, Qt::ConnectionType type = Qt::AutoConnection)

即将sender的signal与当前对象的functor函数连接。

以上五种重载中,最后一个参数是缺省的。在高级应用中有可能会用到,这边先列举一下官方的说明,做个备忘。如果以后有空闲再详细研究。

ConectionType

 

参考书目:

.0官方文档

《C++ GUI Programming with Qt 4 2nd Edition》(为了方便起见,以后的文章提到时简称为《2nd》)

豆子空间:《Qt学习之路》,《Qt学习之路2

二零一五年三月十一日

顾毅写于厦门

» 订阅本站:http://www.xiamengy.net/
» 除非注明,本站文章均属原创。转载请注明来源:风中落叶——顾毅的博客 » Qt备忘录之三:slots与signals初探

发表评论

Required fields are marked *.