浅谈Qt事件的路由机制:鼠标事件
请注意,本文是探讨文章而不是教程,是根据实验和分析得出的结果,可能是错的,因此欢迎别人来探讨和纠正。
这几天对于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事件的路由机制:鼠标事件的更多相关文章
- 事件监听机制——鼠标事件MouseEvent
鼠标事件 鼠标事件包括鼠标的双击.左击.右击.中间键等等,本文进行事件加载进行简单介绍,具体可以参考键盘事件. import java.awt.*; import java.awt.event.*; ...
- 【ASP.NET MVC系列】浅谈ASP.NET MVC 路由
ASP.NET MVC系列文章 [01]浅谈Google Chrome浏览器(理论篇) [02]浅谈Google Chrome浏览器(操作篇)(上) [03]浅谈Google Chrome浏览器(操作 ...
- 浅谈Linux中的信号处理机制(二)
首先谢谢 @小尧弟 这位朋友对我昨天夜里写的一篇<浅谈Linux中的信号处理机制(一)>的指正,之前的题目我用的“浅析”一词,给人一种要剖析内核的感觉.本人自知功力不够,尚且不能对着Lin ...
- Qt事件系统之二:鼠标事件和滚轮事件
在Qt中,事件作为一个对象,继承自 QEvent 类,常见的有键盘事件 QKeyEvent.鼠标事件 QMouseEvent 和定时器事件 QTimerEvent 等,与 QEvent 类的继承关系图 ...
- 浅谈 Qt 布局那些事
Qt 布局那些事是本文介绍的内容,直接进入主题.GridLayout是一个非常强大的布局管理器,它可以实现很多复杂的布局,名字中暗示它将所有控件放置在类似网格的布局中.^__^GridLayout有两 ...
- Qt 隐藏标题栏 窗口移动 鼠标事件
摘要 隐藏标题栏 头文件声明鼠标移动虚函数 .cpp文件实现功能 1 setWindowFlags(Qt::FramelessWindowHint | windowFlags()); 无标题栏移动窗体 ...
- 浅谈SQL Server内部运行机制
对于已经很熟悉T-SQL的读者,或者对于较专业的DBA来说,逻辑的增删改查,或者较复杂的SQL语句,都是非常简单的,不存在任何挑战,不值得一提,那么,SQL的哪些方面是他们的挑战 或者软肋呢? 那就是 ...
- 13-jQuery事件绑定和常用鼠标事件
# 关于事件 ## 事件绑定 1.**基本绑定** > $(element).click(function(){})>> $(element).dblclick(function() ...
- 浅谈Linux中的信号处理机制(一)
有好些日子没有写博客了,自己想想还是不要荒废了时间,写点儿东西记录自己的成长还是百利无一害的.今天是9月17号,暑假在某家游戏公司实习了一段时间,做的事情是在Windows上用c++写一些游戏英雄技能 ...
随机推荐
- wxpython 树形控件全选和取消全选
#encoding:utf-8 import wx import wx.lib.agw.customtreectrl as CT class MyFrame(wx.Frame): def __init ...
- iOS第三方开源库的吐槽和备忘(转)
原文:http://www.cocoachina.com/industry/20140123/7746.html 做iOS开发总会接触到一些第三方库,这里整理一下,做一些吐槽. 目前比较活跃的社区 ...
- UNIX网络编程---传输层:TCP、UDP、SCTP(二)
UNIX网络编程----传输层:TCP.UDP.SCTP 一.概述 本章的焦点是传输层:包括TCP.UDP.和SCTP(流控制传输协议).SCTP是一个较新的协议,最初设计用于跨因特网传输电话信令. ...
- `npm install --save --save-exact react-native` failed
当你使用命令行创建一个项目 react-native init 项目名称 后出现以下错误 Installing react-native package from npm... /bin/sh: ...
- 查看EBS R12应用中使用CONTEXT_FILE的版本及路径
SELECT * FROM APPLSYS.FND_OAM_CONTEXT_FILES;
- Csharp递归和循环实现折半查找
static bool whilehalf(int n) { ; //低位 ; //高位 ; while(low <= hight) { if(n> arr[c]) { low = c + ...
- linux创建用户和组
linux下创建用户(一) Linux 系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统.用户的账号一方面可以帮助系 ...
- 查看mysql字符集及修改表结构
MySQL 乱码的根源是的 MySQL 字符集设置不当的问题,本文汇总了有关查看 MySQL 字符集的命令.包括查看 MySQL 数据库服务器字符集.查看 MySQL 数据库字符集,以及数据表和字段的 ...
- 移动web开发
在现代网页开发中,新增了一个移动设备网页开发,在这样的需求下,你需要考虑如何将移动web和pc web同步处理 /* * 浏览器如何识别移动设备 * */ var ua = navigator.use ...
- sim卡中的汉字存储格式
Sim卡中的ucs2格式 Sim卡中的中文都是以ucs2格式存储的,ucs2和unicode只是字节序不同,unicode是小头在前,ucs2是大头在前. Ucs2与GB2312互换可以用VC中的Wi ...