void MainWindow::mousePressEvent(QMouseEvent *e)
qDebug()<<"mainwindow pressed";
e->ignore();
点击按钮,运行结果如下:
这也就验证了事件的传递方向,子控件先接收到事件,父控件后接收到事件。尤其注意代码中的e->ignore();这句的作用是使得事件能够继续流向父控件;与之相反的是e->accept();它将事件拦截,父控件将无法收到已经被accept过的事件;重写的事件处理函数中,如果不写accept或ignore,那么默认为:事件被accept(拦截)!
上面的代码为例,如果QButtonEx::mousePressEvent()函数中不写e->ignore(),或者写e->accept(),那么
MainWindow::mousePressEvent()函数将不会被触发,运行结果中只能看到打印:button pressed
二、事件过滤器
考虑一下上面的这种事件流向机制,有何不足?先来看这几种应用场景:
1、某事件发生了,我想在父控件先处理,处理完再让子控件处理(和前面所述的流向相反)
2、某些控件已经重写了一些事件处理函数,我想临时让这些事件处理函数失效,待会再恢复
3、Qt 创建了QEvent事件对象之后,会调用QObject的event()函数处理事件的分发。显然,我们可以在event()函数中实现拦截的操作。由于event()函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当麻烦,更不用说重写event()函数还得小心一堆问题。https://blog.csdn.net/gusgao/article/details/48917427
4、绘制了一个按钮,按钮上又覆盖上一层label,那么这个label会遮住button,使得这个按钮无法被点击到。
这些问题都可以用事件过滤器来解决,事件过滤器的作用用一句话来说就是:
任意对象都可以提前拦截其他任意对象的事件,拦截到的事件都会在本对象的eventFilter函数中被接收到,程序员可以决定拦截并处理后是否继续放行。
举例:一个按钮被点击,本应是按钮先收到点击事件,通过事件过滤器,可以让窗体先收到这个事件,窗体再决定是否把这个事件继续传播给按钮。从事件过滤器的功能来看,不妨叫做:事件监视器、事件拦截器。
假设有两个对象,分别叫做“老师A”和“学生a”,实现事件过滤器需要做两个工作:
1、学生a给老师A授权,允许老师查看自己的所有事件;
2、老师A重写eventFilter函数,对拦截到的学生的事件进行处理;
第1个工作就是一句代码,例如:
ui->pushButton->installEventFilter(this);//pushButton设置mainwindow作为自己的事件监视器(事件过滤器)
第2个工作就是重写监视对象A的成员函数:
bool MainWindow::eventFilter(QObject *watched, QEvent *event)//pushButton的所有事件都要先流到这里,这里放行后pushButton才能收到事件
if(watched == ui->pushButton)//确认被监视的对象
if(event->type() == QEvent::MouseButtonPress)//确认事件的类型
QMouseEvent *e = static_cast<QMouseEvent *>(event);//前面已经确认过事件类型为鼠标类型,所以这里可以放心的进行静态转换
qDebug()<<"Filter mainwindow MouseButtonPress";
if(e->button() == Qt::LeftButton)//鼠标左键
return true; //true=拦截
return false; //false=继续传播
return false; //false=继续传播
分别单击鼠标左、右键,运行的结果分别为:
------
可以看到:
1、按钮并没有收到左键被按下事件,因为这一事件被监视对象给拦截后,没有放行;
2、按钮收到了右键按下事件,这一事件依次被以下函数执行:监视对象的eventFilter函数-->按钮的mousePressEvent()函数-->窗口的mousePressEvent()函数
一、事件的流向QT的各种控件(QObject的子类)都有事件处理成员函数,例如:bool QObject::event(QEvent *e);//所有事件dragEnterEvent(QDragEnterEvent *);//拖拽进入事件focusInEvent(QFocusEvent *);//获得焦点事件mousePressEvent(QMouseEvent *);//鼠标压下...
需要使用windeployqt.exe
为了方便,我把他的路径添加到环境变量中C:\Qt\Qt5.14.2\5.14.2\mingw73_32\bin
在生成的exe下运行windeployqt Test.exe
可以单独把exe复制出来,在exe位置执行命令,这样就不会包含之前的中间文件了
发现即使运行了windeployqt同样会有一些dll没有复制进去,如果设置.
bool QObject::event(QEvent *e);//所有事件
dragEnterEvent(QDragEnterEvent *);//拖拽进入事件
focusInEvent(QFocusEvent *);//获得焦点事件
mousePressEvent(QMouseEvent *);//鼠标压下事件
····//还有几十个各种类型的事件,不一一列举了,任何一个控件的帮助文件里都可以查到
这些事件需要继承父类
bool eventFilter(QObject *obj, QEvent *event);
Qt的事件过滤由以上两个方法实现,首先安装一个事件过滤器,然后重写bool eventFilter(QObject *obj, QEvent *event)。
filterObj表示事件筛选器对象,它接收发送到此QObject对象的所有事件。筛选器可以停止事件,也可以将事件转发给此Q
我们先看下另外两个相关的方法,一个是给对象安装某个事件过滤器,一个是移除对应的事件过滤器。
void QObject::installEventFilter(QObject *filterObj)
void QObject::removeEventFilter(QObject *obj)
下方代码使用 installEventFilter方法 给