Signals & Slots(Qt5) (三)

2014-11-24 02:54:24 · 作者: · 浏览: 7
bool point);
};

//略过moc不关心的一些析构函数和成员函数
class LcdNumber : public QFrame
{
Q_OBJECT
public:
LcdNumber(QWidget *parent = 0);
signals:
void overflow();
public slots:
void display(int num);
void display(double num);
void display(const QString &str);
void setHexMode();
void setDecMode();
void setOctMode();
void setBinMode();
void setSmallDecimalPoint(bool point);
};
>如果你继承自QWidget, 基本上肯定需要在构造函数中加上parent参数, 把它传递给基类的;

>当LcdNumber被要求显示一些非法的值时, 会发送overflow() signal;

>如果你不关心溢出, 或者知道不可能发生溢出, 你可以忽略overflow() signal; 可以不把它关联到任何slot上;

>相反如果你想要在溢出时调用两个不同的错误处理函数, 简单地关联到两个不同的slots就行; Qt会按照关联的次序调用两个函数;

>Slot是被用来获得其他widget状态改变的信息的接收函数; 在示例代码中, LcdNumber使用它去设置显示的数字; 因为display()是类的一个接口, 所以这个slot设置为public;

>多个示例程序关联QScrollBar的valueChanged() signal到了dispaly() slot, 因此LCD数字会不停得在scrollbar上显示;

Note display()被重载overload了; 当你把一个signal和一个slot关联起来, Qt会选择适合的版本; 如果是使用callback, 你将不得不自己来找出5个不同的函数名字并且控制不同的类型;

具有默认参数的Signals和Slots


>signal和slot的原型可能包含了参数, 参数可能有默认值. 考虑QObject::destroyed():


[cpp]
void destroyed(QObject* = 0);

void destroyed(QObject* = 0);
>当一个QObject被删除, 它会发出QObject::destoryed() signal. 我们想要捕获这个signal, 不论在哪我们可能有一个dangling reference指向被删除的QObject, 这样我们可以清除它; 一个合适的slot原型可能是:


[cpp]
void objectDestroyed(QObject* obj = 0);

void objectDestroyed(QObject* obj = 0);
>有多种方式使用QObject::connect()来关联signal-slot, 第一种是以函数指针:


[cpp]
connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);

connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
>使用函数指针有很多优点. 首先, 允许编译器检查signal的参数是否和slot的参数兼容; 需要的话参数也能被编译器隐式地转换;

>你也可以使用C++11 lamdas表达式:

[cpp]
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });

connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
Note 如果你的编译器不支持C++ 11可变参数模板 variadic templates, 这个语法只能在signal和slot具有小于或等于6个参数的情况下有效;


>还有一个方法是使用SIGNAL和SLOT宏. 关于是否在SIGNAL()和SLOT()宏中引入参数; 如果参数有默认值, 规则是传到SIGNAL()中的函数原型的参数个数必须少于传到SLOT()中的函数原型;

[cpp]
//以下这些都能工作
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

//以下这些都能工作
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

[cpp]
//这个无法工作,因为slot预期的是接收一个参数QObject,这个signal不会发出参数, connection会报错;
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

//这个无法工作,因为slot预期的是接收一个参数QObject,这个signal不会发出参数, connection会报错;
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));Note 当使用宏的QObject::connect()重载, 编译器不会检查signal-slot的参数;

更多Signal-Slot的使用

>如果你想得到发送signal的sender的信息, Qt提供了QObject::sender()函数, 返回一个指向发送signal的对象的指针;


>当遇到很多signals关联到一个相同的slot的情况, 并且这个slot需要对每个signal作出不同的处理时, 可以用QSignalMapper类;

>假设你有三个push buttons, 用来决定打开哪种文件: Tax File, Accounts File, Report File.

>为了打开正确的文件, 使用QSignalMapper::setMapping()把所有的clicked() signals和QSignalMapper对象map起来; 然后把文件的QPushButton::clicked() signal和QSignalMapper::map() slot关联起来;