Qt知识笔记(八)—— 鼠标和事件
鼠标事件
默认情况下,触发事件需要点击一下,才能触发。可设置为自动触发:
setMouseTracking(true);
鼠标事件有单机,双击,释放,移动,滑轮
单机:void mousePressEvent(QMouseEvent *event);
双击:void mouseDoubleClickEvent(QMouseEvent *event);
释放:void mouseReleaseEvent(QMouseEvent *event);
移动:void mouseMoveEvent(QMouseEvent *event);
滑轮:void wheelEvent(QWheelEvent *event);
想要实现指定控件的鼠标事件,要将控件提升为自定义类,然后在类中重写对应的鼠标事件。
指定鼠标键
如何指定鼠标左键还是右键触发事件呢?
在重写函数中进行判断即可,如:
//鼠标左键按下void myLabel::mousePressEvent(QMouseEvent *ev){if(ev->button()==Qt::LeftButton){......}}//鼠标左键释放void myLabel::mouseReleaseEvent(QMouseEvent *ev){if(ev->button()==Qt::LeftButton){......}}//鼠标左键移动void myLabel::mouseMoveEvent(QMouseEvent *ev){if(ev->button()==Qt::LeftButton){......}}
鼠标联合按键
鼠标点击、释放、移动三个时间的具体实现,if条件判断的是事件是否由鼠标左键触发,如果三个条件全部写成
ev->button()==Qt::LeftButton
,运行时会发现鼠标移动事件不做反应。解决的方法是将原本的条件改为
ev->buttons() == Qt::LeftButton
这样,在点击鼠标左键后进行移动,就会做出反应。
button() 仅仅返回的是触发事件时的按键,而buttons() 返回的是鼠标的状态,包括鼠标左中右三键的联合信息。
//&为位与运算符,只有在所有状态下均为左键按下时为真if(ev->buttons()& Qt::LeftButton){......}
右键菜单
鼠标右键弹出菜单可以通过重写鼠标事件实现,也可以通过重写从父类继承的虚函数 void contextMenuEvent(QContextMenuEvent *event)来实现。
1.在类中声明
protected:// 如果窗口设置了 Qt::DefaultContextMenu 策略, // 点击鼠标右键该函数被Qt框架调用voidcontextMenuEvent(QContextMenuEvent *event)override;
2.在这个窗口类的构造函数设置右键菜单策略
setContextMenuPolicy(Qt::DefaultContextMenu);
3.在这个窗口类的源文件中重写事件处理器函数 contextMenuEvent()
voidMainWindow::contextMenuEvent(QContextMenuEvent *event){......}
除了上面的策略,还有两个策略Qt::ActionsContextMenu和Qt::CustomContextMenu,这两个策略这里就不介绍了。
事件
在 Qt 框架内部为我们提供了一系列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤->事件分发->事件处理几个阶段。Qt 窗口中对于产生的一系列事件都有默认的处理动作,如果我们有特殊需求就需要在合适的阶段重写事件的处理动作。
事件分发过程:
1.事件产生之后,Qt 应用程序对象调用 notify() 函数将事件发送到指定的窗口
2.事件在发送过程中可以通过事件过滤器进行过滤,默认不对任何产生的事件进行过滤
3.事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类
4.事件分发器将分类之后的事件(如鼠标事件、键盘事件等)分发给对应的事件处理器函数进行处理
事件处理器
每个事件处理器函数都对应一个唯一的事件,事件处理器函数都是回调函数,也就是说作为使用者只需要指定函数的处理动作,关于函数的调用是不需要进行操作的,当某个事件被触发,Qt 框架会调用对应的事件处理器函数。
常用的事件处理器函数:
鼠标事件
键盘事件
窗口重绘
窗口关闭
重置窗口大小
可以在 Qt 的任意一个窗口类中重写这些事件处理器函数来重定义它们的行为。
事件分发器
当事件产生被发送到对应的窗口之后,窗口并不会直接处理这个事件,而是对这些事件进行细分,然后根据事件的类型再次进行分发,对应的事件处理器函数得到这个分发的事件之后就开始处理这个事件。
关于窗口事件的分发,对应一个事件分发器
[overridevirtualprotected]boolQWidget::event(QEvent *event);
关于事件类型的判断是基于参数完成的,这个参数是一个 QEvent 类型的对象
这里有两个常用的API
//让窗口接受传递过来的事件,事件不会向上层窗口(父窗口)传递voidQEvent::accept();//让窗口忽略传递过来的事件,事件被传递给父窗口(向上传递)voidQEvent::ignore();
可以在事件分发器中进行拦截,不让某些触发的事件进入到当前窗口中。
事件分发器函数的返回值:
如果传入的事件已被识别并且处理,则需要返回 true,否则返回 false。如果返回值是 true,那么 Qt 会认为这个事件已经处理完毕,不会再将这个事件发送给其它对象,而是会继续处理事件队列中的下一事件。
如果想过滤某个事件,只需要在判断出这个事件之后直接返回 true 就可以了。
在event()函数中,调用事件对象的 accept() 和 ignore() 函数是没有作用的,不会影响到事件的传播。
在窗口中过滤掉鼠标按下的事件:
boolMainWindow::event(QEvent *ev){if(ev->type()== QEvent::MouseButtonPress ||
ev->type()== QEvent::MouseButtonDblClick){// 过滤调用鼠标按下的事件returntrue;}//调用了父类的事件分发器函数returnQWidget::event(ev);}
事件过滤器
除了使用事件分发器来过滤 Qt 窗口中产生的事件,还可以通过事件过滤器过滤相关的事件。当 Qt 的事件通过应用程序对象发送给相关窗口之后,窗口接收到数据之前这个期间可对事件进行过滤,过滤掉的事件就不能被继续处理了。
使用:
1.给要被过滤事件的类对象安装事件过滤器
2.在要进行事件过滤的类中重写从QObject类继承的虚函数eventFilter()
3.如果想过滤掉这个事件,停止它被进一步处理,返回 true,否则返回 false
事件过滤器和被安装过滤器的组件必须在同一线程, 否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两个组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。
版权归原作者 洞洞鞋小公子 所有, 如有侵权,请联系我们删除。