重写事件

#include<QEvent>

先继承一个Qt中的类,例如QLabel

1
2
3
4
5
6
7
8
9
10
11
#ifndef LABELX_H
#define LABELX_H

#include <QLabel>
class LabelX : public QLabel
{
Q_OBJECT
public:
explicit LabelX(QWidget *parent = nullptr);
};
#endif // LABELX_H

QLabel中有两个个函数enterEvent和leaveEvent,要重写的就是这两个事件,检测鼠标进入与退出标签

1
2
3
4
5
6
7
8
9
10
11
void LabelX::enterEvent(QEnterEvent *event){
Q_UNUSED(event);
this->setText(QString("enter" + QString::number(++cnt0)));
}

void LabelX::leaveEvent(QEvent *event){
Q_UNUSED(event);
//qDebug() << ++ cnt1;
this->setText(QString("leave" + QString::number(++cnt1)));
}

注意这两个函数的参数类型不一样(在之前的版本似乎是一样的,但在Qt6中有变化)

事件监控

但是当需要让一个标签只负责检测输入,一个检测输出,这样就不行了。这时候我们需要重写QWidget中的eventFilter函数。
lblLeave->installEventFilter(this);用于为标签加上事件监视器,那么当有事件传入时,先交给this也就是这个页面处理。下面是处理函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
bool EnterLeaveWidget::eventFilter(QObject *watched, QEvent *event)//传入监控对象与事件类型
{
if(watched == lblEnter){
if(event->type() == QEvent::Enter){
lblEnter->setText(QString("进入%1次").arg(++enterTimes));
return true;
}
else if(event->type() == QEvent::Leave){
return true;
}
}
else if(watched == lblLeave){

if(event->type() == QEvent::Leave){
lblLeave->setText(QString("退出%1次").arg(++leaveTimes));
return true;
}
else if(event->type() == QEvent::Enter){
return true;
}
}
return false;
}

函数返回值true表示事件已处理,则这个被监控的Object就不再处理;false表示事件未处理,需要继续处理。

鼠标事件

按下/拖动/释放事件

QLabel中这三个鼠标函数都可以重写,获取到鼠标的信息。

1
2
3
4
5
6
7
   void mousePressEvent(QMouseEvent *ev) override;
void mouseMoveEvent(QMouseEvent *ev) override;
void mouseReleaseEvent(QMouseEvent *ev) override;
ev->button();//鼠标按下的按钮
ev->buttons();//鼠标在移动时使用,因为此时可以有多个按键按下
ev->pos();//相对位置
ev->globalPos;//全局位置

事件过滤器

限制label的活动范围

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
bool PressMoveReleaseWidget::eventFilter(QObject *watched, QEvent *event){
if(watched == lbx){
if(event->type() == QEvent::MouseButtonPress){
QMouseEvent* mseInitial = static_cast<QMouseEvent*>(event);
pntMouse = mseInitial->globalPosition().toPoint();
pntLabel = lbx->pos();
}
else if(event->type() == QEvent::MouseMove){
QMouseEvent* mseLater = static_cast<QMouseEvent*>(event);
QPoint pntNow = pntLabel + mseLater->globalPosition().toPoint() - pntMouse;
lbx->move(pntNow);
if(pntNow.x() < 0){
lbx->move(0, pntNow.y());
if(pntNow.y() < 0)
lbx->move(0, 0);
if(pntNow.y() > this->height() - lbx->height())
lbx->move(0,this->height() - lbx->height());
}

if(pntNow.x() > this->width() - lbx->width()){
lbx->move(this->width() - lbx->width(), pntNow.y());
if(pntNow.y() < 0)
lbx->move(this->width() - lbx->width(), 0);
if(pntNow.y() > this->height() - lbx->height())
lbx->move(this->width() - lbx->width(),this->height() - lbx->height());
}
if(pntNow.y() < 0){
lbx->move(pntNow.x(), 0);
if(pntNow.x() < 0)
lbx->move(0, 0);
if(pntNow.x() > this->width() - lbx->width())
lbx->move(this->width() - lbx->width(), 0);
}
if(pntNow.y() > this->height() - lbx->height()){
lbx->move(pntNow.x(), this->height() - lbx->height());
if(pntNow.x() < 0)
lbx->move(0, this->height() - lbx->height());
if(pntNow.x() > this->width() - lbx->width())
lbx->move(this->width() - lbx->width(), this->height() - lbx->height());
}
}
else if(event->type() == QEvent::MouseButtonRelease){
qDebug() << static_cast<QMouseEvent*>(event)->pos() << Qt::endl;
}
}
return false;
}

这是一种比较麻烦的实现方法

注意:Qt6中倡导使用globalPosition().toPoint()来获取全局位置

1
2
3
4
5
6
7
8
9
10
11
12
qint64 iX = pntNow.x(), iY = pntNow.y();
qint64 iSX = iX, iSY = iY;
if(iX < 0)
iSX = 0;
if(iX > this->width() - lbx->width())
iSX = this->width() - lbx->width();
if(iY < 0)
iSY = 0;
if(iY > this->height() - lbx->height())
iSY = this->height() - lbx->height();

lbx->move(iSX, iSY);

也可以用空间换时间,代码更加简洁

键盘事件

重写这两个函数

1
2
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);

获取键值

1
2
3
4
5
6
7
8
9
10
   switch(event->key()){
case Qt::Key_Return:
qDebug() << "return";
break;
}
if(event->modifiers() == Qt::ControlModifier)

//三个按键同时按下
if(event->modifiers() == (Qt::ControlModifier | Qt::ShiftModifier) && event->key() == Qt::Key_A)

定时器事件

重写函数

1
2
protected:
void timerEvent(QTimerEvent* event);

可以在按下按钮时触发定时器,即

1
2
3
    id1 = startTimer(10);
id2 = startTimer(20);
//startTimer函数会返回一个定时器的id, 之后根据ID对定时器进行管理

timerEvent会检查定时器是否到时间

1
2
3
4
5
6
7
8
9
10
void TimerWidget::timerEvent(QTimerEvent *event)
{
if(event->timerId() == id1){
lbl1->move((lbl1->x() + 5) % this->width(), lbl1->y());

}
if(event->timerId() == id2){
lbl2->move((lbl2->x() + 5) % this->width(), lbl2->y());
}
}

停止定时器即killTimer(id)

使用QTimer类

1
2
3
4
5
6
7
8
9
10
#include <QTimer>
QTimer *timer1, *timer2;
timer1 = new QTimer(this), timer2 = new QTimer(this);
connect(timer1, &QTimer::timeout, this, &TimerWidget::onTime1Out);
connect(timer2, &QTimer::timeout, this, &TimerWidget::onTime2Out);

//开始timer1
timer1.start(20);
//停止timer1
timer1.stop();

拖放事件

文件拖入输入框(QTextEdit)直接读取文件内容,自定义类继承QTextEdit实现功能

重写函数

1
2
3
4
void dragEnterEvent(QDragEnterEvent *e); //文件拖入
void dragLeaveEvent(QDragLeaveEvent *e); //文件离开
void dragMoveEvent(QDragMoveEvent* e); //文件移动
void dropEvent(QDropEvent* e); //放入文件

构造函数中要加入this->setAcceptDrops(true);才能启用文本拖放功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

void TextEditX::dragEnterEvent(QDragEnterEvent *e) //进入事件
{
e->mimeData()->hasText():
//检查拖拽内容是否包含纯文本。
//如果用户拖拽的是文本(例如从记事本或浏览器中拖拽的文字),返回 true。

e->mimeData()->hasUrls():
//检查拖拽内容是否包含文件路径。
//如果用户拖拽的是文件(例如从文件管理器中拖拽的文件),返回 true。

e->acceptProposedAction():
//如果拖拽内容是文本或文件,则接受拖拽操作。

e->ignore():
//如果拖拽内容不支持(如图片、二进制文件等),则忽略拖拽操作。
}

放入文件后的事件处理

1
2
3
4
5
6
7
8
9
10
11
12
void TextEditX::dropEvent(QDropEvent *e)
{
qDebug() << "dropEvent";
QList<QUrl> urls = e->mimeData()->urls();
if(urls.empty())
return;
QString fileName = urls.first().toLocalFile();
QFile file(fileName);
if(file.open(QIODevice::ReadOnly)){
this->setPlainText(file.readAll());
}
}

滚轮调整文字大小

1
2
3
4
5
6
7
8
9
10
11
12
void TextEditX::wheelEvent(QWheelEvent *e)
{
if(QApplication::keyboardModifiers() == Qt::ControlModifier){
if(e->angleDelta().y() > 0)
this->zoomIn();
else if(e->angleDelta().y() < 0)
this->zoomOut();
}
else {
QTextEdit::wheelEvent(e);
}
}

右键菜单事件

熟悉的重写函数

1
2
3
4
5
6
7
8
void ContextWidget::contextMenuEvent(QContextMenuEvent *event)
{
QMenu *menu = new QMenu();
menu->addAction(cut);
menu->addAction(paste);
menu->exec(event->globalPos());
delete menu;
}
  • QAction的定义与槽函数
    1
    2
    3
    4
    5
    6
    7
    8
    9
    cut = new QAction("剪切", this);
    paste = new QAction("粘贴", this);
    connect(cut, SIGNAL(triggered(bool)), this, SLOT(onAction()));
    connect(paste, SIGNAL(triggered(bool)), this, SLOT(onAction()));
    void ContextWidget::onAction()
    {
    QAction *act = (QAction*)sender();
    qDebug() << act->text();
    }