1、QEvent和事件处理
QEvent为事件对象,其派生类有QMouseEvent、QKeyEvent、QPaintEvent、QCloseEvent、QTimterEvent等,事件可以有多种类型,如鼠标事件有鼠标按下、释放、移动等。在事件处理方法中会发出相应的信号,如下面的鼠标释放事件中会发出clicked()信号,如果设置了clicked()信号的槽方法那么就会执行它。QObject子类都可以接收和处理事件。
void mouseReleaseEvent(QMouseEvent *e);
处理一个事件可以有5中方法, 下面前三种事件处理动作的先后顺序是③->②->①。:
①、重新实现部件的paintEvent()、mousePressEvent()等事件处理方法。如果我们想要父部件也来处理子部件的事件,那么可以在子部件的事件处理方法的最后调用事件对象的ignore()方法来设置忽略该事件,那么事件就会转给父部件来处理。
②、重新实现QObject的event()方法,在event()方法中提前对事件进行处理:
bool MainWindow::event(QEvent *e) { if(e->type() == QEvent::KeyPress) //键盘按下事件 ; else ; return QMainWindow::event(e); //执行event()方法的默认操作 }
③、在对象上安装事件过滤器,调用对象的installEventFilter(QObject *)方法来安装事件过滤器,重写过滤器对象的eventFilter()方法来实现对事件的提前处理,这种方法的好处就是可以在eventFilter()方法中对多个部件的事件进行处理:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); ui->pushButton->installEventFilter(this); ui->textEdit->installEventFilter(this); ui->spinBox->installEventFilter(this); } bool MainWindow::eventFilter(QObject *obj, QEvent *e) { if(obj == ui->pushButton) { if(e->type() == QEvent::MouseButtonPress) { //do something... return true; //不再传递给后面的消息处理流程 } else { return false; //其它事件进行进一步的处理 } } else if(obj == ui->textEdit) { if(e->type() == QEvent::Wheel) { QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(e); //转换为发生的事件类型 if(wheelEvent->delta() > 0) ui->textEdit->zoomIn(); else ui->textEdit->zoomOut(); return true; } } else if(obj == ui->spinBox) { if(e->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e); //转换为发生的事件类型 if(keyEvent->key() == Qt::Key_Space) { ui->spinBox->setValue(0); return true; } } } return QMainWindow::eventFilter(obj, e); //其它事件正常处理 }
④、重新实现notify方法,对象需要继承自QApplication,一般不常用。
⑤、在QApplication对象上安装事件过滤器,这将会使用一个全局的事件过滤器,一般不常用。
2、QMouseEvent和QWheelEvent
如下为对鼠标事件的一系列操作:
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); //修改鼠标指针光标为张开的小手 QCursor cursor; //创建光标对象 cursor.setShape(Qt::OpenHandCursor); //设置光标形状 setCursor(cursor); //使用光标 } void Widget::mousePressEvent(QMouseEvent *e) { if(e->button() == Qt::LeftButton) //鼠标左键按下,修改鼠标指针光标为握住的小手 { QCursor cursor; cursor.setShape(Qt::ClosedHandCursor); QApplication::setOverrideCursor(cursor); //临时改变鼠标指针光标形状 m_ptOffset = e->globalPos() - pos(); //获取鼠标指针位置和当前窗口位置的差值(QPoint类型) } else { //鼠标右键按下,修改鼠标指针光标为一张图片 QCursor cursor(QPixmap("../image.png")); QApplication::setOverrideCursor(cursor); } } void Widget::mouseReleaseEvent(QMouseEvent *e) //鼠标按键释放 { QApplication::restoreOverrideCursor(); //恢复鼠标指针光标形状 } void Widget::mouseMoveEvent(QMouseEvent *e) //鼠标按住左键移动的话移动当前部件 { if(e->buttons() & Qt::LeftButton) //鼠标左键按下 { QPoint pt = e->globalPos() - m_ptOffset; //获得新的部件位置 move(pt); //移动部件 } } void Widget::mouseDoubleClickEvent(QMouseEvent *e) //双击鼠标左键全屏或恢复原来大小 { if(e->buttons() & Qt::LeftButton) //左键双击 { if(windowState() != Qt::WindowFullScreen) setWindowState(Qt::WindowFullScreen); //设置全屏 else setWindowState(Qt::WindowNoState); //恢复以前的大小 } } void Widget::wheelEvent(QWheelEvent *e) //设置滚轮滑动来控制编辑器字体大小 { if(e->delta() > 0) //delta获得滚轮移动的距离,滚轮旋转一下默认移动的是15,向上滚动为15,向下滚动为-15 ui->textEdit->zoomIn(); //字体放大 else ui->textEdit->zoomOut(); //字体缩小 }
3、QKeyEvent
下面是按下Ctrl + M键后最大化窗口的示例:
void Widget::keyPressEvent(QKeyEvent* e) { if(e->modifiers() == Qt::ControlModifier) //按下了Ctrl键,Crl和Shift等需要使用modifiers()方法获取 { if(e->key() == Qt::Key_M && !e->isAutoRepeat()) //按下了M键,普通按键通过key()方法获得,如果是一直按下按键的话isAutoRepeat()返回true setWindowState(Qt::WindowMaximized); //窗口最大化 else if(e->key() == Qt::Key_M && e->isAutoRepeat()){ qDebug() << "df"; } } }
4、QTimerEvent
QTimer为定时器类,以下是其使用示例:
QTimer* timer = new QTimer(this); //创建定时器对象 connect(timer, SIGNAL(timeout()), this, SLOT(timerOut())); //将定时器超时信号关联到当前类的timerOut方法槽上 timer->start(1000); //开启1秒超时的定时器
下面是实现一个只运行一次的定时器的方法
QTimer::singleShot(10000, this, SLOT(close())); //10秒后执行部件的close()成员方法来关闭窗口
调用QObject的startTimer()方法也可以开启一个定时器,timerEvent()为定时事件处理方法。
5、sendEvent()、postEvent()
QCoreApplication的sendEvent()和postEvent()方法用来发送一个事件,sendEvent()会立即处理给定的事件,postEvent将事件投递到消息队列中,且postEvent投递的QEvent事件对象必须在堆上创建,我们不用手动释放它,因为事件队列会自动释放它。
下面是使用sendEvent()发送向上按键按下消息到sinBox部件的示例,其中qApp为当前程序QApplication对象的全局指针:
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); QKeyEvent keyEvent(QEvent::KeyPress, Qt::Key_Up, Qt::NoModifier); qApp->sendEvent(ui->spinBox, &keyEvent); }