现在对于这个过程还有一个疑问,就是它是如何定时消失掉的呢? QTooltip
QApplication会把延时未动鼠标的事件
QEvent::ToolTip发送到 QWidget..
然后QWidget在事件中判断!
d->QTooltip.isEmpty()是否为空.
空的话就ignore这个事件.
非空就通过QHelpEvent得到鼠标坐标.(static_cast<QHelpEvent*>(event)->globalPos())并
显示出来.
[size=; FONT-SIZE: 9pt,9pt]
[font='YaHei Consolas Hybrid']可以不定义类对象,而直接使用类的成员函数,一般使用静态成员函数,不是thiscall调用.所以也不需要有对象的this指针. [size=; FONT-SIZE: 9pt,9pt]
[font='YaHei Consolas Hybrid']Qt 的tool tip今天要给我做的qt控件加个tooltip,嗯,应该不难的。不过,还是先把tooltip的来龙去脉弄清楚先的。
QEvent::ToolTip的前端.来自MouseMove中的定时器QApplication中有一个叫作
toolTipWakeUp的定时器,当鼠标移动到某个QWidget上一段时间不动后它便会被触发。当鼠标离此QWidget时,它便会被停止。
有MouseMove才能触发该定时器.例如在
其他触发定时器关闭的动作后
没有移动鼠标,那么定时器就没有启动.
每次MouseMove重新设置定时器.
定时器时间设为20呢?每次都达不到
相关代码在
QApplication::notify 函数中:
//处理QEvent::MouseMove消息,
//在鼠标移动事件里,每次都重新设定WakeUp定时器(因为移动了)
//在鼠标其他事件中,每次都停止WakeUp定时器(因为有其他鼠标事件产生了)
//在WakeUp定时器响应中,关闭此定时器,开启FallAsleep定时器,
//针对这个定时器id,生成事件QEvent::ToolTip.发送到QWidget上
//并且启用FallAsleep定时器用于控制ToolTip显示时长,此时d->toolTipFallAsleep.isActive()为激活状态
//鼠标再移动的话,激活的是20ms定时器,而20ms过小,都不会得到及时的处理而阻断了该定时器的功能?(因为已经显示出来了)
//而在FallAsleep响应中,关闭定时器,并且关闭Tooltip的显示(没有).然后开始新一轮的响应了.
//那么这个ToolTip显示是如何被其他事件阻断的呢?使定时器睡眠就能关闭ToolTip的显示?
//是在那个20ms的定时器里,先判断FallAsleep是否激活,然后判断一轮这些事件,有了就关闭么?
//为什么系统的ToolTip要经过很长延时才被关闭了,再哪儿关闭的?
// bool QApplication::notify(QObject *receiver, QEvent*e)内
case QEvent::MouseMove: 内
if (e->type() == QEvent::MouseMove && mouse->buttons() == 0)
{
d->toolTipWidget = w;
d->toolTipPos =relpos;
d->toolTipGlobalPos =mouse->globalPos();
d->toolTipWakeUp.start(d->toolTipFallAsleep.isActive()?20:700, this);
}
//如果在过程中出现下列事件,则使睡眠定时器
// User input and windowactivation makes tooltips sleep
switch (e->type()) {
caseQEvent::Wheel:
case QEvent::ActivationChange:
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::FocusOut:
case QEvent::FocusIn:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
d->toolTipFallAsleep.stop();
// fall-through
case QEvent::Leave:
d->toolTipWakeUp.stop();
default:
break;
}
QEvent::ToolTip的发送:sendEvent()tooltip事件是由上面提到的定时器触发的。
并在
QApplication::Event 函数中通过
响应对应的定时器来发送到指定的窗口中。
if (te->timerId() == d->toolTipWakeUp.timerId()){
d->toolTipWakeUp.stop();// 先停止WakeUp定时器
if (d->toolTipWidget) {
QWidget *w = d->toolTipWidget->window();
//show tooltip if WA_AlwaysShowToolTips is set, orif
// any ancestor ofd->toolTipWidget is the active
// window
bool showToolTip = w->testAttribute(Qt::WA_AlwaysShowToolTips);// 判断该属性,如果有就直接跳过下面的while了.
while (w && !showToolTip) {// 判断是否有容纳ToolTip的控件
showToolTip = w->isActiveWindow(); //如果没被激活
w = w->parentWidget(); //指向父窗口
w = w ? w->window() : 0; //父窗口不是顶级窗口
}
if (showToolTip) { // 如果有
QHelpEvent e(QEvent::ToolTip, d->toolTipPos, d->toolTipGlobalPos); // 则生成ToolTip事件
QApplication::sendEvent(d->toolTipWidget, &e); // 发送之
if (e.isAccepted()) // 如果被某一个Widget接受了
d->toolTipFallAsleep.start(2000, this); // 以2000ms启动FallAsleep计时器
}
}
}else if(te->timerId() == d->toolTipFallAsleep.timerId()) {
d->toolTipFallAsleep.stop();
}
QWidget对 QEvent::ToolTip的响应好吧,tool tip的事件已经知道是怎么发送到指定的QWidget了,
现在就看看QWiget是怎么处理ToolTip事件的,
QWidget::Event()的相关代码段如下:
case QEvent::ToolTip:
if (!d->toolTip.isEmpty())
QToolTip::showText(static_cast<QHelpEvent*>(event)->globalPos(),d->toolTip, this);
else
event->ignore();
break;
至于QToolTip自身又是怎么显示的,就不详细记述了。其实,就是显示一个
QLabel打完收工~
以下是自己实现的.
#include "tooltips1.h"
#include<QPushButton>
#include <QBasicTimer>
#include <QToolTip>
tooltips1::tooltips1(QWidget *parent,Qt::WFlags flags)
: QWidget(parent, flags)
{
ui.setupUi(this);
setToolTip("hello");
QPushButton *btn = new QPushButton("hello",this);
btn->show();
}
tooltips1::~tooltips1()
{
}
bool tooltips1::event(QEvent *e)
{
if(e->type() == QEvent::ToolTip)
{
//头文件声明QBasicTimer timer;
timer->start(500,this);
//QToolTip::showText(static_cast<QHelpEvent*>(e)->globalPos(),"hello");
}
else if (e->type() == QEvent::Timer)
{
QTimerEvent *timerevent = static_cast<QTimerEvent*>(e);
if(timerevent->timerId()== timer->timerId())
{
QToolTip::hideText();
timer->stop();
}
}
return QWidget::event(e);
}
现在对于这个过程还有一个疑问,就是它是如何定时消失掉的呢?