QT消息机制和事件 - 鼠标事件、键盘按下事件、绘图事件、定时器事件处理
- 开发
- 28
-
事件
- 事件(event)是由系统或者Qt本身在不同时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如键盘事件等。另一些事件则由系统自动发出,如定时器事件。
Qt消息循环机制
- Qt程序需要在main函数创建一个QApplication对象,然后调用它的exec函数,这个函数就是开始Qt的事件循环。在执行exec函数之后,程序将进入事件循环来监听应用程序的事件。
- 当应用程序监听到事件触发后,先将请求交给事件过滤器,过滤后再交给事件分发器,由事件分发器交给具体的事件处理器进行处理。
- 事件过滤器,事件分发器和事件处理器,默认都会对事件进行处理,如果我们想要自己处理事件,就重写对应的事件函数。然后在对应的事件函数中,进行相应的处理。
- 一般来说,重写事件处理函数的场景比较多,事件过滤和事件分发,基本上交给系统处理就可以了,我们不用自己处理。为了说明事件过滤器和事件分发器的作用,因此下面也重写了事件过滤函数和事件分发函数。
- 由于重写事件处理器函数比较常用,阅读时可以先查看事件处理,再查看事件过滤和事件分发。
事件过滤
事件过滤函数
- bool eventFilter(QObject *watched, QEvent *event);
- 返回值是bool类型,如果返回true,表示用户要处理这个事件,不向下分发事件。
示例
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void keyPressEvent(QKeyEvent *event);
bool event(QEvent* ev);
bool eventFilter(QObject *watched, QEvent *event);
private:
Ui::Widget *ui;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QMouseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
installEventFilter(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->type() == QEvent::KeyPress){
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Tab){
QMessageBox::question(this, "提示", "事件处理函数中Tab键按下", QMessageBox::Yes);
}
}
}
bool Widget::event(QEvent *ev)
{
if(ev->type() == QEvent::KeyPress){
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
if(keyEvent->key() == Qt::Key_Tab){
QMessageBox::question(this, "提示", "事件分发函数中Tab键按下", QMessageBox::Yes);
return true;
}
}
return QWidget::event(ev);
}
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
if(watched == this){
if(event->type() == QEvent::KeyPress){
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Tab){
QMessageBox::question(this, "提示", "Tab键按下", QMessageBox::Yes);
return true;
}
}
}
return QWidget::eventFilter(watched, event);
}
- 如果在事件过滤器中处理了事件并且不往下传递,那么在事件分发器和事件处理器都不会接收到相应的事件。
事件分发
事件分发函数
- bool event(QEvent* ev);
- 返回值是bool类型,如果返回true,表示用户要处理这个事件,不向下分发事件。
示例
- 下来通过一个例子演示下,在事件分发函数中,处理键盘的tab键按下事件,并且处理后不向下传递,这样对应的事件处理函数就接收不到该事件了。
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void keyPressEvent(QKeyEvent *event);
bool event(QEvent* ev);
private:
Ui::Widget *ui;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QMouseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->type() == QEvent::KeyPress){
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Tab){
QMessageBox::question(this, "提示", "事件处理函数中Tab键按下", QMessageBox::Yes);
}
}
}
bool Widget::event(QEvent *ev)
{
if(ev->type() == QEvent::KeyPress){
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
if(keyEvent->key() == Qt::Key_Tab){
QMessageBox::question(this, "提示", "Tab键按下", QMessageBox::Yes);
return true;
}
}
return QWidget::event(ev);
}
- 演示
- 通过示例可以看到,虽然在事件处理函数中对tab键按下进行了处理,但由于在事件分发函数中,并未向下传递tab键按下事件,因此事件处理函数并未被触发。
事件处理
- 事件触发后,先经过事件过滤器进行过滤,再经过事件分发器,下发到具体的事件处理器中,默认事件处理器也会自动处理事件,如果想要自己处理,就可以重写事件处理函数。
- QObject类是所有Qt类的父类,因此所有Qt类都可以继承QObject类的事件处理函数,QObject类的事件函数主要是定时器事件函数,由系统自动触发。
- QWidget类是所有Qt窗口类的事件函数,因此所有Qt窗口类都可以继承QWidget类的事件处理函数,QWidget类的事件函数比较多,比如键盘按下事件,鼠标移动事件等,QWidget类的事件函数,主要由用户触发。
QObject类的事件处理函数
- virtual void timerEvent(QTimerEvent *event)
QWidget类的事件处理函数
- virtual void closeEvent(QCloseEvent *event)
- virtual void hideEvent(QHideEvent *event)
- virtual void showEvent(QShowEvent *event)
- virtual void resizeEvent(QResizeEvent *event)
- virtual void keyPressEvent(QKeyEvent *event)
- virtual void keyReleaseEvent(QKeyEvent *event)
- virtual void mouseDoubleClickEvent(QMouseEvent *event)
- virtual void mouseMoveEvent(QMouseEvent *event)
- virtual void mousePressEvent(QMouseEvent *event)
- virtual void mouseReleaseEvent(QMouseEvent *event)
- virtual void paintEvent(QPaintEvent *event)
示例1:窗口事件处理
- 接下来我们通过一个例子来演示下对窗口关闭和窗口重设大小的事件如何处理
- 创建一个类,继承于QWidget类
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void closeEvent(QCloseEvent *event);
void resizeEvent(QResizeEvent *event);
private:
Ui::Widget *ui;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QCloseEvent>
#include <QResizeEvent>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::closeEvent(QCloseEvent *event)
{
int retStatus = QMessageBox::question(this, "提示", "确定关闭窗口吗?", QMessageBox::Yes | QMessageBox::No);
if(retStatus == QMessageBox::Yes){
event->accept();
}else{
event->ignore();
}
}
void Widget::resizeEvent(QResizeEvent *event)
{
qDebug()<<"old size : "<<event->oldSize();
qDebug()<<"new size : "<<event->size();
}
- 效果展示
示例2:鼠标事件处理
- 再实现一个对鼠标按下、鼠标松开和鼠标移动的事件处理流程。
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
private:
Ui::Widget *ui;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
#include <QMouseEvent>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ui->label->setText("鼠标正常");
}
Widget::~Widget()
{
delete ui;
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton){
ui->label->setText("鼠标左键按下");
}else if(event->button() == Qt::RightButton){
ui->label->setText("鼠标右键按下");
}else{
ui->label->setText("鼠标按下");
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
ui->label->setText("鼠标松开");
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
QString msg;
msg = "鼠标移动(" + QString::number(event->x()) + "," + QString::number(event->y()) + ")";
ui->label->setText(msg);
}
- 效果展示
示例3:绘图事件处理
- 处理绘图事件算是很常用的一个功能,下面通过一个示例进行简单说明
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QEvent>
#include <QPainter>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void paintEvent(QPaintEvent* e);
private:
Ui::Widget *ui;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::paintEvent(QPaintEvent *e)
{
QPainter painter(this);
painter.drawLine(QPoint(0, 0), QPoint(100, 100));
QPen pen(QColor(255, 0, 0));
pen.setWidth(3);
pen.setStyle(Qt::DotLine);
painter.setPen(pen);
painter.drawRect(QRect(0, 0, 100, 100));
QBrush brush(Qt::green);
brush.setStyle(Qt::Dense1Pattern);
painter.setBrush(brush);
painter.drawEllipse(QPoint(150, 50), 50, 50);
painter.drawText(QRect(0, 150, 150, 150), "HELLO");
painter.drawPixmap(100, 100, QPixmap(":/gray.jpg"));
}
- 演示
- 绘图事件比较特殊,默认是系统自动触发,但是还可以手动进行触发,那就是在函数中调用 update() 函数,调用之后也会自动触发绘事件,对应的绘图事件处理函数会被执行。比如可以在鼠标点击槽函数中调用 update() 函数,这里就不进行演示了。
示例4:定时器事件处理
- 定时器事件由系统触发,可以重写处理函数,在其中进行相应操作,这也是非常常用的一个功能。
- 头文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QEvent>
#include <QTimerEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected:
void timerEvent(QTimerEvent *e);
private:
Ui::Widget *ui;
int timerId;
};
#endif
- 源文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QDebug>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
timerId = startTimer(1000);
}
Widget::~Widget()
{
killTimer(timerId);
delete ui;
}
void Widget::timerEvent(QTimerEvent *e)
{
qDebug()<<"定时器事件触发";
}
原文地址:https://blog.csdn.net/new9232/article/details/134625282
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。
本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:https://www.suanlizi.com/kf/1732084097901268992.html
如若内容造成侵权/违法违规/事实不符,请联系《酸梨子》网邮箱:1419361763@qq.com进行投诉反馈,一经查实,立即删除!