信号(signal) 和 槽(slot) 是qt 的一个特色(不知道怎样说好不好, 吾喷).
QObject::connect(button, SIGNAL(clicked()),&app, SLOT(quit()));
上面的是本人第一次用到信号和槽的代码, 这句代码的作用是点击按钮后, 应用程序关闭.
以前写vc 的程序, 都是从类向导(vs6)或者属性(vs05)那里添加消息方法的, 如果要跟其他对象进行交互, 代码写起来不止繁琐, 耦合性还很高. 如果是手动添加信息方法, 麻烦死了! 信号和槽的方式我个人挺喜欢的.
信号和槽的方式跟 javascript 很相像呢, 这是我的第一感觉! button.onclick = clickFun; 或者 button.attachEvent("onclick", clickFun); 这两个是js 在IE 下注册事件的方式. 他们有一些共同点, 需要一个目标元素, 如button; 一个事件方法, 如onclick; 一个实施方法, 如 clickFun.(准确来是, 这个是一个click事件, clickFun是一个函数对象)
对比QObject::connect(button, SIGNAL(clicked()),&app, SLOT(quit())); 目标元素都是button, 事件方法onclick和clicked, 实施方法 clickFun和quit() 也有了. 大家应该都注意到了吧, qt 还多了一个事件的实施对象app , 并且槽方法也不是顺便找一个成员方法或者非成员方法就可以的(这个大家可以自己测试一下).
看看QPushButton 的 父类QAbstractButton 的头文件里面关于信号和槽的方法的声明:
public Q_SLOTS:
void setIconSize(const QSize &size);
void animateClick(int msec = 100);
void click();
void toggle();
void setChecked(bool);
Q_SIGNALS:
void pressed();
void released();
void clicked(bool checked = false);
void toggled(bool checked);
Q_SLOTS, Q_SIGNALS 和 SIGNAL(SLOT) 都是宏, 它们具体是怎么声明的本人不清楚. 有一件事情本人倒是清楚, 就是信号和槽的方法都必须显式地声明 .
信号方法要显式声明, 这个本人可以理解, 但是槽也要显式声明, 本人表示不理解了. 如 QSpinBox 类的成员方法setSingleStep(int) 不是槽方法, 当我想在某个信号放出后, 调用 QSpinBox 对象的setSingleStep(int) 方法, 怎么办呢? 我可以写一个类, 继承 QSpinBox, 并且定义setSingleStep(int)为槽方法(本人没测试过), 这个新类, 明显没啥实际的新东西呢!
在<C++ GUI Programming with Q4 2nd> 的第二章第2节 Signals and Slots in Depth, 最后有一个方法的定义:
void Employee::setSalary(int newSalary)
{
if (newSalary != mySalary)
{
mySalary = newSalary;
emit salaryChanged(mySalary);
}
}
emit salaryChanged(mySalary); 这句是重点呢, salaryChanged(int) 是一个信号方法, emit 是关键字还是宏呢?
emit salaryChanged(mySalary); 这行代码的作用是发出一个 salaryChanged() 的信号. 看来, Qt 的信号不单单是信息或者事件, 还可以是自定义的信号. Qt 接收到salaryChanged()信号后, 就会去找跟该信号连接并且可用的槽, 调用这些槽方法.
像signals, slots, emit 等关键字, 在Qt 4.10 以后的版本, 务必使用 Q_SIGNALS,Q_SLOTS,Q_EMIT 宏替换, 这样做的理由是避免关键字跟其他的C++库冲突, 如Boost 库. 这些宏在 QtCore/qobjectdefs.h 文件里面声明.
一个信号可以连接多个槽!
一个槽可以被多个信号连接!
信号与被连接的槽的方法的参数基本上要相同, 如果信号方法的参数数目多于槽方法的参数, 额外的参数将被槽方法忽略!
像热水器的火温度改变了, 温度显示表的数值也要改变这种情况, 用java 语言(不用spring)的实现的话, 一般会考虑用观察者模式, 但是观察者模式, 被观察者要继承一个类, 观察者要实现一个接口, 都不干脆! 如果用Qt 的信号和槽实现, 简单方便!
---------------------------------------------------------------可爱的分割线------------------------------------------------------
参考: http://www.qteverywhere.com/qt/qt4gossip/CustomSignalSlot.html (这个好像是林信良(良葛格)写的)