mfc提供了CToolTipCtrl、CMFCToolTipCtrl等类用于控件的tooltip。一直存在一个疑问,mfc是如何获取鼠标在控件上的悬停时间的呢?按照常规的思路,当鼠标停止移动时开始计时,但是系统根本没有鼠标停止运动这个事件,或者说系统也无法得知鼠标停止运动。
在翻看vtkBalloonWidget和vtkHoverWidget的源码时,偶然发现vtk是如何计算鼠标在对象上的悬停时间的,我想mfc也是大概的思路吧。
// Okay, define the events for this widget. Note that we look for extra events
// (like button press) because without it the hover widget thinks nothing has changed
// and doesn't begin retiming.
this->CallbackMapper->SetCallbackMethod(
vtkCommand::LeftButtonPressEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::MiddleButtonPressEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::RightButtonPressEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::MouseWheelForwardEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::MouseWheelBackwardEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::MouseMoveEvent, vtkWidgetEvent::Move, this, vtkHoverWidget::MoveAction);
this->CallbackMapper->SetCallbackMethod(
vtkCommand::TimerEvent, vtkWidgetEvent::TimedOut, this, vtkHoverWidget::HoverAction);
看上面的代码,主要有两个事件响应函数,分别是MoveAction和HoverAction。其中HoverAction就是计时器到达指定的悬停时间后,弹出信息提示文字。关键是MoveAction,鼠标点击,鼠标移动,滚轮滚动等都会调用MoveAction函数,下面是改函数的实现。
vtkHoverWidget* self = reinterpret_cast<vtkHoverWidget*>(w);
if (self->WidgetState == vtkHoverWidget::Timing)
{
self->Interactor->DestroyTimer(self->TimerId);
}
else // we have already timed out, on this move we begin retiming
{
self->WidgetState = vtkHoverWidget::Timing;
self->SubclassEndHoverAction();
self->InvokeEvent(vtkCommand::EndInteractionEvent, nullptr);
}
self->TimerId = self->Interactor->CreateRepeatingTimer(self->TimerDuration);
通过上面的代码不难发现,一旦鼠标发生移动,如果此时正在悬停计时,则停止计时,如果没有悬停计时,则开始计时,即开始记录悬停的时间。这其实是一种反向思维,既然无法知道鼠标什么时候停止移动,但是知道鼠标什么时候移动,只要移动,就停止计时,没有计时,就开始计时,从而实现计算悬停时间的功能。