SIGNAL-SLOT是Qt的一大特色,使用起来十分方便。在传统的AWT和Swing编程中,我们都是为要在
监听的对象上添加Listener监听器。被监听对象中保存有Listener的列表,当相关事件发生时,被监听
对象会通知所有Listener。而在Qt中,我们只需通过connect方法连接两个对象上的方法就可以了,非常
方便、优雅地实现了传统的观察者Observer模式。
Qt是如何办到的呢?对于发出SIGNAL的对象,我们需要在其头文件定义中声明Q_Object宏,之后Qt的
预处理器MOC会为我们自动添加上相应的代码来实现SIGNAL-SLOT机制。这与AspectJ自定义了Javac
编译器很类似,都是通过增强编译器来自动添加相应的代码。
增强编译或增加预处理太复杂,怎样能够简单的实现这种机制呢?首先我们实现一个类似的QObject类,
需要发射SIGNAL的类都要继承它。在QObject类中,我们自动为其子类提供监听器列表,查找SLOT方法,
信号发射等功能。
QObject.java
1.在连接方法中,我们将信号和新建的ReceiverSlot类保存到Map中,从而将它们关联起来。
2.在创建ReceiverSlot时,我们解析SLOT方法名,如将slot(String,String)解析为方法slot,参数两个String。
如果解析失败我们就认为该SLOT仍是一个信号,也就是SIGNAL-SIGNAL的连接。这种情况下,我们需要
传递调用的不是receiver的SLOT方法,而是emit方法继续发射信号。
3.解析后,如果是SIGNAL-SLOT的连接,那我我们根据方法名和参数找到该方法,准备反射调用。
4.发射信号时,我们取到所有与该SIGNAL关联的ReceiverSlot类,逐个发射信号。
之后,我们实现一个它的子类QWidget,将常用的Swing控件都封装在QWidget的子类中,为这些控件提供
常见的预定义的SIGNAL,像Qt中的clicked和returnPressed。
QWidget.java
以下是封装了JButton和JTextField的QWidget子类。
QPushButton.java
QLineEdit.java
下面我们来写个测试类实验下Java版的SIGNAL-SLOT机制,依旧是之前的浏览器的例子。
AddressBar.java
TabBar.java
MainWindow.java
测试一下吧,运行起来的效果就是这样。
新建Tab页和前往该地址事件都可以成功地从AddressBar传递到TabBar。怎么样,这种Java版的
SIGNAL-SLOT是不是很方便。多开拓自己的视野,借鉴优秀的思想,我们才能做出更好的设计!
希望你喜欢本文。