第16章 Qt中的观察者模式

一个GUI应用程序常常提供了多种视图来查看同一个数据对象,一旦该对象发生变化,所有视图都会发生变化。

例如Excel中对数据的多种显示和处理方式:

Excel Example

我们可以使用观察者(Observer)模式来实现这一功能:

  • 被显示的数据被称为主对象(Subject)
  • 显示这些数据的视图被称为观察者(Observer)

Qt中的信号与槽机制使用了观察者模式:

  • 发出信号的对象就是该模式中的主对象;
  • 提供槽函数的对象就是该模式中的观察者
  • connect函数连接一个信号与一个槽,实际上对主对象添加了一个观察者;反之,disconnect函数删除了一个观察者。
  • 当信号产生时,所有观察者的槽函数都会被调用,观察者可以更新自己的状态。

信号与槽提供了一种简单的观察者模式。然而,在Qt中的事件处理机制中,需要使用者显式地使用该模式。

16.1 事件处理机制

在应用程序和用户交互过程中,会产生各种事件(Event),如鼠标单击、移动事件,键盘按键事件等等;

操作系统也会向应用程序发送各种事件,如窗口或对话框对象首次被显示在屏幕上时,Windows系统会向该对象发送“绘制”事件(paint),通知该对象绘制自己。

应用程序本身也可以产生事件,如一个计时器(QTimer)对象会周期性地发送“计时时间到”时间,等等。

在Qt中,使用QEvent类来描述事件。该类有很多子类,对各种类型的事件进行描述,如QMouseEvent,QPaintEvent, QTimerEvent等等。

为了方便对于这些事件的描述,QEvent类中定义了相应的枚举常量,如QEvent::Timer等等。

对于底层事件,通常使用者无需修改相应的处理函数;当需要不同与Qt默认的方式处理事件时,可以通过重写事件处理函数来实现。


16.2 事件滤波器 (Event Filter)

对于具有父子关系的两个控件来说,子控件检测到事件,可以通过返回false的方式将事件传递给父控件处理。

然而对于没有父子关系的两个控件,这种事件传递机制就会失效。相应的解决方案时Qt的事件滤波器(Event Filter)

设置QScrollArea为另一控件的观察者示例代码:

void QScrollArea::setWidget(QWidget* widget) {
  ...
  widget->installEventFilter(this);
  ...
}
bool QScrollArea::eventFilter(QObject* o, QEvent* e) {
  if (o == d->widget && e->type() == QEvent::Resize)
    d->updateScrollBars();
  return false;
}

本文整理自《Qt中的C++技术》张波 著

posted @ 2018-09-09 18:46  brilliantdo  阅读(2785)  评论(0)    收藏  举报