重写事件
#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
|
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); 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);
|
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.start(20);
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():
e->mimeData()->hasUrls():
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(); }
|