请注意,本文是探讨文章而不是教程,是根据实验和分析得出的结果,可能是错的,因此欢迎别人来探讨和纠正。

  这几天对于Qt的事件较为好奇,平时并不怎么常用,一般都是用信号,对于事件的处理,一般都是需要响应键盘按键事件的时候,也用得毫无问题,因此也没怎么注意过,翻了下一般qt的教材《精通Qt4编程(第二版)》,里面12.1是这么说的。

当用户按下一个鼠标键时,这个事件首先被发给当前拥有焦点的窗口部件。

  看到这里,我第一反应是,真的是这样吗,我表示十分地好奇,于是就赶忙试验了一下。代码比较简单,没有注释,相信都能看懂,main函数省略,没什么改动。

  父窗口.h

#ifndef DIALOG_H
#define DIALOG_H #include <QDialog> namespace Ui {
class Dialog;
} class myButton; class Dialog : public QDialog
{
Q_OBJECT public:
explicit Dialog(QWidget *parent = );
~Dialog(); private:
Ui::Dialog *ui;
myButton* btn;protected:
void mousePressEvent(QMouseEvent *);
// bool eventFilter(QObject *, QEvent *);
}; #endif // DIALOG_H

  父窗口.CPP

#include "dialog.h"
#include "ui_dialog.h"
#include "mybutton.h"
#include <QApplication>
#include <QDebug>
#include <QMouseEvent> Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
btn=new myButton(tr("测试父按钮"),this);
} Dialog::~Dialog()
{
delete ui;
} void Dialog::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"void Dialog::mousePressEvent(QMouseEvent *)";
}

  子窗口.h

#ifndef MYBUTTON_H
#define MYBUTTON_H #include <QPushButton> class myButton : public QPushButton
{
Q_OBJECT
public:
myButton(const QString &str,QWidget *parent); signals: public slots: protected: void mousePressEvent(QMouseEvent *e);
}; #endif // MYBUTTON_H

  父窗口.cpp

#include "mybutton.h"
#include <QEvent>
#include <QDebug> myButton::myButton(const QString &str, QWidget *parent) :
QPushButton(str,parent)
{
} void myButton::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"void myButton::mousePressEvent(QMouseEvent *e)";
}

  子窗口和父窗口都安装了鼠标按下事件的响应函数,好了,试一下吧。

  结果是这样的,可以看到,是父窗口的事件处理器被触发了,而焦点窗口应该是子窗口的按钮,那么是否是Qt的某些机制,使得鼠标按键造成了焦点的转移呢,难道其实焦点在按下鼠标之后转移到了父窗口上?还是还试一下吧。

  把父窗口和子窗口的mousePressEvent修改为

qDebug()<<"void Dialog::mousePressEvent(QMouseEvent *)"<<hasFocus();
qDebug()<<"void myButton::mousePressEvent(QMouseEvent *e)"<<hasFocus();

  再来运行下,看下结果

  可以看到,父窗口依旧是没有焦点的,所以上面的猜测是错误的吗?

  继续向自己提问,是否是因为父窗口的原因呢,如果鼠标按下的是子窗口会怎么样,继续尝试

  在父窗口的构造函数最后增加一行代码

setFocus();

  继续尝试,在子窗口按钮上按下鼠标,会是什么结果呢。

  结果很奇怪,在父窗口中点击鼠标,确实是获得焦点的,然后再点子窗口,按钮子窗口也获得了焦点,然后再点父窗口,再也获得不到焦点了。

  继续写代码测试,这次子类化一个QWidget,然后重写mousePressEvent,因为QWidget默认是分发事件的,因此稍作修改,让他阻断事件。

void myWidget::mousePressEvent(QMouseEvent *e)
{
e->accept();
qDebug()<<"void myWidget::mousePressEvent(QMouseEvent *e)"<<hasFocus();
}

  然后新窗口构造函数中对新窗口稍微修改下样式,以区分2个窗口

QHBoxLayout *layout=new QHBoxLayout;
QLabel *label=new QLabel(tr("新窗口"));
layout->addWidget(label);
setLayout(layout);
resize(,);

  在父窗口中注释掉原来的button子窗口,new一个新的widget子窗口,现在父窗口和子窗口都是QWidget

    w=new myWidget(this);
w->setStyleSheet("background-color:red;");

  运行下看看,发现两个窗口都没有焦点

  在父窗口构造函数中加上

setFocus();

  然后交叉点击父窗口和子窗口,你会发现焦点永远在父窗口上,如果setFous在子窗口,就永远在子窗口,如果都加了,就按照代码顺序。

  可见,这是按钮一个默认机制,焦点的夺回,如果别的窗体设置了焦点,然后点击鼠标按下按钮,按钮会夺回焦点,再也不还了,除非你再次设置焦点。

  再次尝试下,发现即使焦点在子窗口,点击父窗口,消息不会路由到子窗口上。

  在这里得出一个结论,鼠标事件的获得与处理,是根据鼠标点击的窗体所决定的,而不是像书本上说的路由到焦点所在窗体(键盘事件则确实如此,以后再谈),如果子窗口处理鼠标事件的时候,使用ignore分发(默认是accept截获),会再向父窗口传递,直到事件被截获或者到达顶层窗口。

  QPushButton等有click信号的窗体控件,如果处理mousePressEvent,click信号还会被响应吗

  父窗口的构造函数修改为

    ui->setupUi(this);
//w=new myWidget(this);
//w->setStyleSheet("background-color:red;");
btn=new myButton(tr("测试父按钮"),this);

  父窗口的mousePressEvent修改为

void Widget::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"void Widget::mousePressEvent(QMouseEvent *e)"<<hasFocus(); }

  子窗口的按钮构造函数为空白,mousePressEvent修改为(注意,此时子窗口已经变回按钮了)

void myButton::mousePressEvent(QMouseEvent *e)
{ qDebug()<<"void myButton::mousePressEvent(QMouseEvent *e)";
}

  然后给按钮子窗口安装一个槽函数,响应按钮的cilck信号,槽函数自由发挥,能显示是否被调用就行

  可以看到,如果处理了鼠标按键后调用父类方法,是可以响应click消息的,如果注释掉return,则没有click消息,可以自行测试。

  最后一个问题,我不调用父类方法,而是使用ignore分发,能有click消息吗?

  注释掉return,如果你刚才没注释掉的话,在按钮的mousePressEvent里加上一句代码

e->ignore();

  然后运行程序,点击按钮

  可以看见,父窗口收到了子窗口传来的鼠标事件,但是click信号并没有被触发。

  今天就到这吧,我写本文的原因不是教别人,而是阐述疑惑与观点,因为一句话说不清,在这里求教育求指正,有什么错误尽管提,谢谢各位了。

  过几天再和大家讨论下键盘事件的路由,拖放事件的看法,以及过滤器的一些疑惑与测试。

浅谈Qt事件的路由机制:鼠标事件的更多相关文章

  1. 事件监听机制——鼠标事件MouseEvent

    鼠标事件 鼠标事件包括鼠标的双击.左击.右击.中间键等等,本文进行事件加载进行简单介绍,具体可以参考键盘事件. import java.awt.*; import java.awt.event.*; ...

  2. 【ASP.NET MVC系列】浅谈ASP.NET MVC 路由

    ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...

  3. 浅谈Linux中的信号处理机制(二)

    首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...

  4. Qt事件系统之二:鼠标事件和滚轮事件

    在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图 ...

  5. 浅谈 Qt 布局那些事

    Qt 布局那些事是本文介绍的内容,直接进入主题.GridLayout是一个非常强大的布局管理器,它可以实现很多复杂的布局,名字中暗示它将所有控件放置在类似网格的布局中.^__^GridLayout有两 ...

  6. Qt 隐藏标题栏 窗口移动 鼠标事件

    摘要 隐藏标题栏 头文件声明鼠标移动虚函数 .cpp文件实现功能 1 setWindowFlags(Qt::FramelessWindowHint | windowFlags()); 无标题栏移动窗体 ...

  7. 浅谈SQL Server内部运行机制

    对于已经很熟悉T-SQL的读者,或者对于较专业的DBA来说,逻辑的增删改查,或者较复杂的SQL语句,都是非常简单的,不存在任何挑战,不值得一提,那么,SQL的哪些方面是他们的挑战 或者软肋呢? 那就是 ...

  8. 13-jQuery事件绑定和常用鼠标事件

    # 关于事件 ## 事件绑定 1.**基本绑定** > $(element).click(function(){})>> $(element).dblclick(function() ...

  9. 浅谈Linux中的信号处理机制(一)

    有好些日子没有写博客了,自己想想还是不要荒废了时间,写点儿东西记录自己的成长还是百利无一害的.今天是9月17号,暑假在某家游戏公司实习了一段时间,做的事情是在Windows上用c++写一些游戏英雄技能 ...

随机推荐

  1. 通过属性集名称获取属性集id

    Mage::getModel('eav/entity_attribute_set')->load('属性集名称', 'attribute_set_name')->getAttributeS ...

  2. Mac/ios 模拟器 测试模拟慢网速

    原文:http://www.heyuan110.com/2015/06/16/Mac%E6%B5%8B%E8%AF%95%E6%A8%A1%E6%8B%9F%E6%85%A2%E7%BD%91%E9% ...

  3. 【线段树】【4-6组队赛】Problem H

    Problem Description #include <iostream> #include <algorithm> using namespace std; int n, ...

  4. 3.C#/.NET编程中的常见异常(持续更新)

    1.Object reference not set to an instance of an object. 未将对象引用(引用)到对象的实例,说白了就是有个对象为null,但是你在用它点出来的各种 ...

  5. HTML5 元素拖放

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  6. 《think in python》学习-3

    函数 函数是指用于进行某种计算的一系列语句的有名称的组合. type(32) 就是一个函数调用的例子 类型转换函数 python提供了一些可将某个值从一种类型转换为另外一个类型的内置函数 int(32 ...

  7. OpenCV学习(3)--Mat矩阵的操作

    CvMat的矩阵结构 typedef struct CvMat { //矩阵中元素的类型 int type; //行数据长度 int step; /* for internal use only */ ...

  8. node 的 异步 数据库 调用 处理

    相信很多人在使用node 的时候, 一方面会觉得他强大的异步性感到很方便. 但是有时候我们却非要程序能按我们自己的想法 去串行的执行我们的思路. 同样我在编写的过程中也遇到类似的问题,比如for 和 ...

  9. Docker容器的网络连接

    Docker容器的网络连接 Docker容器的网络连接 我们用ifconfig命令来查看网络设备 我们可以看到上面有个叫docker0的网络设备,docker守护进程就是通过docker0为docke ...

  10. Ajax应用常见的HTTP ContentType设置

    文章出处:Ajax应用常见的HTTP ContentType设置 ajax开发中, 常遇到下面的几种情况: 1 服务端需要返回一段普通文本给客户端 2 服务端需要返回一段HTML代码给客户端 3 服务 ...