事件的处理
(1)重新实现部件的paintEvent()、mousePressEvent()等事件处理函数。这是最常用的一种方法,不过它只能用来处理特定部件的特定事件。
(2)重新实现notify()函数。这个函数功能强大,提供了完全的控制,可以在事件过滤器得到事件之前就获得它们。但是,它一次只能处理一个事件。需要继承自QApplication类
(3)向QApplication对象上安装事件过滤器。因为一个程序只有一个QApplication对象,所以这样实现的功能与使用notify()函数是相同的,优点是可以同时处理多个事件。需要继承自QApplication类
(4)重新实现event()函数。QObject类的event()函数可以在事件到达默认的事件处理函数之前获得该事件。
(5)在对象上安装事件过滤器。使用事件过滤器可以在一个界面类中同时处理不同子部件的不同事件。
事件的传递
新建C++类
将mylineedit.h文件内容修改如下
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QDebug>
#include <QLineEdit>
#include <QWidget>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr);
protected:
void keyPressEvent(QKeyEvent *event) override;
};
#endif // MYLINEEDIT_H
mylineedit.cpp文件修改为如下所示
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
#include <QWidget>
MyLineEdit::MyLineEdit(QWidget *parent):QLineEdit(parent)
{
}
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("MyLineEdit::keyPressEvent");
}
widget.h文件,添加类前置声明:
class MyLineEdit;
添加函数声明:
protected:
void keyPressEvent(QKeyEvent *event) override;
添加一个private对象指针:
MyLineEdit *lineEdit;
在Widget类的构造函数中添加代码:
lineEdit = new MyLineEdit(this);
lineEdit->move(100,100);
添加事件处理函数的定义:
void Widget::keyPressEvent(QKeyEvent *event)
{
Q_UNUSED(event);
qDebug() << tr("Widget::keyPressEvent");
}
这里自定义了一个MyLineEdit类,它继承自QLineEdit类,然后在Widget界面中添加了一个MyLineEdit部件。
现在运行程序,这时光标焦点在行编辑器中,随便在键盘上按一个按键,比如按下A键,则Qt Creator的应用程序输出栏中只会出现“"MyLineEdit::keyPressEvent”,
到mylineedit.cpp文件中的keyPressEvent()函数最后添加如下一行代码,让它忽略掉这个事件。
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("MyLineEdit::keyPressEvent");
QLineEdit::keyPressEvent(event);
}
再运行程序,按下A键,那么在以前输出的基础上又输出了“"Widget::keyPressEvent”,
但是现在出现了一个问题,就是行编辑器中无法输入任何字符,为了让它可以正常工作,用户还需要在mylineedit.cpp文件的keyPressEvent()函数中添加一行代码,
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("MyLineEdit::keyPressEvent");
QLineEdit::keyPressEvent(event);
event->ignore();
}
这里调用了MyLineEdit父类QLineEdit的keyPressEvent()函数来实现行编辑器的默认操作。这里一定要注意代码的顺序,ignore()函数要在最后调用。
总结
在这里,我们通过调用父类 QLineEdit 的 keyPressEvent() 函数来实现行编辑器的默认操作。特别需要注意的是,调用 ignore() 函数来忽略当前事件处理的顺序至关重要,并且应该在最后执行。这样可以确保先执行完父类的默认行为,然后再决定是否忽略当前事件。
使用事件过滤器
在mylineedit.h文件中添加public函数声明:
bool event(QEvent *event) override;
在mylineedit.cpp文件中对该函数进行定义:
void MyLineEdit::event(QKeyEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
qDebug() << tr("MyLineEdit::event");
}
return QLineEdit::event(event);
}
进入widget.h文件中进行public函数的声明:
bool eventFilter(QObject *obj,QEvent *event) override;
到widget.cpp文件中,在构造函数的最后添上一行代码:
lineEdit->installEventFilter(this);
添加事件过滤器函数的定义:
bool Widget::eventFilter(QObject *obj,QEvent *event)
{
if(obj == lineEdit)
{
if(event->type() == QEvent::KeyPress)
{
qDebug() << tr("Widget:eventFilte");
}
}
return QWidget::eventFilter(obj,event);
}
在事件过滤器中,先判断该事件的对象是不是lineEdit,如果是,再判断事件类型。最后返回了QWidget类默认的事件过滤器的执行结果。
首先是widget的过滤事件被执行,
然后是MyLineEdit的事件keyPressEvent
接着是MyLineEdit 的
最后是Widget的keyPressEvent
需要注意,event()函数和事件处理函数是在焦点部件内进行重新定义的,而事件过滤器却是在焦点部件的父部件中进行定义的。
代码
mylineedit.h
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QDebug>
#include <QLineEdit>
#include <QWidget>
#include <QEvent>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = nullptr);
bool event(QEvent *event) override;
protected:
void keyPressEvent(QKeyEvent *event) override;
};
#endif // MYLINEEDIT_H
mylineedit.cpp
#include "mylineedit.h"
#include <QKeyEvent>
#include <QDebug>
#include <QWidget>
MyLineEdit::MyLineEdit(QWidget *parent):QLineEdit(parent)
{
}
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
qDebug() << tr("MyLineEdit::keyPressEvent");
QLineEdit::keyPressEvent(event);
event->ignore();
}
bool MyLineEdit::event(QEvent *event)
{
if(event->type() == QEvent::KeyPress)
{
qDebug() << tr("MyLineEdit::event");
}
return QLineEdit::event(event);
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
QPointF offset;//用来存储鼠标指针位置与窗口位置的差值
//添加声明
protected:
void mousePressEvent(QMouseEvent *event) override;//鼠标按下事件
void mouseReleaseEvent(QMouseEvent *event) override;//
void mouseDoubleClickEvent(QMouseEvent *event) override;//鼠标双击事件
void mouseMoveEvent(QMouseEvent *event) override;//鼠标移动事件
void wheelEvent(QWheelEvent *event) override;//滚轮事件
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include<QMouseEvent>
#include<QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QCursor cursor;//创建光标对象
cursor.setShape(Qt::OpenHandCursor);//设置光标的形状
setCursor(cursor);//使用光标
// setMouseTracking(true);//不按鼠标按键,也可以获取鼠标移动事件,那么就要在构造函数中添加下面一行代码:
}
Widget::~Widget()
{
delete ui;
}
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
QCursor cursor;
cursor.setShape(Qt::ClosedHandCursor);
QApplication::setOverrideCursor(cursor);//使用鼠标指针暂时改变形状
offset = event->globalPosition() - pos();
// qDebug()<< "event->globalPosition()" << event->globalPosition();
// qDebug()<< "pos()" << pos();
// qDebug()<< "offset" << offset;
/*
*event->globalPosition():
*返回的是鼠标在整个屏幕坐标系下的当前位置坐标
*pos():
*返回的是该部件在其父部件(或者整个窗口系统层级中相应的参照位置)中的相对位置坐标
*
*/
}else if(event->button() == Qt::RightButton)
{
//按下鼠标右键时鼠标光标显示的是自定义的图片
//注意:这里的路径实在build目录下寻找
QCursor cursor(QPixmap("../../mymouseevent/logo.png"));
QApplication::setOverrideCursor(cursor);
}
}
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
Q_UNUSED(event);
QApplication::restoreOverrideCursor();//释放鼠标后,鼠标恢复为原状
}
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
if(windowState() != Qt::WindowFullScreen)
{
setWindowState(Qt::WindowFullScreen);//设置为全屏
}else{
setWindowState(Qt::WindowNoState);//恢复之前大小
}
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if(event->buttons() & Qt::LeftButton)
{
QPointF temp;
temp = event->globalPosition() - offset;
// qDebug()<< "event->globalPosition()" << event->globalPosition();
// qDebug()<< "offset" << offset;
move(temp.x(),temp.y());
}
}
void Widget::wheelEvent(QWheelEvent *event)
{
int i =event->angleDelta().y();
qDebug()<< "angleDelta().y()" << i;
if(event->angleDelta().y() > 0)
{
ui->textEdit->zoomIn();//进行放大
}else{
ui->textEdit->zoomOut();//进行缩小
}
}
void Widget::keyPressEvent(QKeyEvent *event)
{
//如果确定按下了 Ctrl 键(即 event->modifiers() == Qt::ControlModifier 条件成立)
if(event->modifiers() == Qt::ControlModifier)
{
if(event->key() == Qt::Key_M){
qDebug()<< "Qt::Key_M" ;
}else if(event->key() == Qt::Key_A){
qDebug()<< "Qt::Key_A" ;
}
}else{
if (event->key() >= Qt::Key_1 && event->key() <= Qt::Key_9)
{
qDebug() << "单独按下数字键: " << event->key();
}
}
}
void Widget::keyReleaseEvent(QKeyEvent *event)
{
}
可以在界面上按住鼠标左键来拖动窗口,双击鼠标左键来使其全屏,按住鼠标右键则使指针变为一个自定义的图片,而使用滚轮可以放大或者缩小编辑器中的内容。
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}