本文共 4564 字,大约阅读时间需要 15 分钟。
事件是一个从QEvent类继承而来的对象,任何从QObject类派生的对象均可通过QObject::event()方法 接收事件,event()函数自身并不处理事件,而是根据事件类型调用响应的事件处理器。例如,QWidget 类中的event()函数实现将鼠标、键盘、重绘等常见事件交给mousePressEvent()、keyPressEvent()、 paintEvent()这些特定的事件处理器进行处理。事件可以被传递。 Qt中处理事件的5中方式: 1、重新实现特定的事件处理器:如mousePressEvent()、keyPressEvent()、paintEvent() 2、重新实现QObject::event()函数 3、在QObject中注册事件过滤器: 如果对象使用installEventFilter()函数注册了事件过滤器,目标对象中的所有事件将首先发给这个 监视对象的eventFilter()函数。 4、在QApplication中注册事件过滤器 5、继承QApplication并重新实现notify()函数:可同时有多个事件过滤器,而notify()函数只有一个 若Qt没有为某个特定事件提供默认的事件处理器,或者提供的默认事件处理器无法满足用户需求,可以 通过重新实现QObject::event()函数来处理: bool MyWidget::event(QEvent* event){ if(event->type() == QEvent::KeyPress){ QKeyEvent *k = static_cast<QKeyEvent*>(event); if(i->key() == Qt::Key_Tab){ //处理Tab键缩进 return true; } }else if(event->type() == MyCustomEventType){ //同上 } return QWidget::event(event); //交给父类处理 } eg: void DrawArea::resizeEvent(QResizeEvent* event){ if(width() > image.width() || height() > image.height()){ int newWidth = qMax(width()+128,image.width()); int newHeight = qMax(height()+128,image.height); .... update(); } QWidget::resizeEvent(event); } //窗口大小改变时调用 void MainWindow::showEvent(QShowEvent* event){ timeId = startTimer(10000); } //主窗口可见时被调用 void MainWindow::hideEvent(QHideEvent* event){ killTimer(timeId); } //窗口不可见时调用 void MainWindow::timerEvent(QTimerEvent* event){ if(event->timerId() == timeId) scribbleArea->clearImage(); } //定时器事件到来时调用 void MainWindow::closeEvent(QCloseEvent* event){ if(maybeSave()){ event->accept(); }else{ event->ignore(); } } //主窗口关闭时调用 /**************************************************************************************************/ 一个QObject实例可以监视另一个QObject实例中的事件,方法是在目标对象中安装事件过滤器。事件过滤器会在事件 到达目标对象之前获取该事件,从而起到监视目标对象事件的效果。 设置事件过滤器需要两步: 1、通过对目标对象调用installEventFilter()来安装事件过滤器 2、在监视对象的eventFilter()函数中处理目标对象的事件 eg: display = new QLineEdit(""); display->installEventFilter(this); //构造函数中安装 bool Digital::eventFilter(QObject* target,QEvent* event){ if(target == display){ if(event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonDblClick || event->type() == QEvent::MouseButtonRelease || event->type() == QEvent::ContextMenu){ QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event); if(mouseEvent->buttons() & Qt::LeftButton){ QPalette newPalette = palette(); newPalette.setColor(QPalette::Base, display->palette().color(QPalette::Text)); newPalette.setColor(QPalette::Text, display->palette().color(QPalette::Bast)); display->setPalette(newPalette); }else{ display->setPalette(palette()); } return true; } } return QDialog::eventFilter(target,event); } /**************************************************************************************************/ 为了加快用户界面响应,防止界面冻结,Qt提供了三种方法: 1、使用多线程 2、在处理耗时事件时频繁调用QApplication::processEvents() 3、推迟耗时事件处理,直到应用程序空闲下来 eg: //使用processEvents()函数 void Dialog::doCopy(){ while(bytesToWrite > 0){ if(isStop){ rFile->close(); wFile->close(); wFile->remove(currentFile); progressBar->setMaximum(totalBytes); progressBar->setValue(0); statusLabel->setText("终止"); saveButton->setEnabled(false); stopButton->setEnabled(false); qApp->processEvents(); return ; }else{ tempBuf = rFile->read(qMin(bytesToWrite,loadSize)); wFile->write(tempBuf); bytesWritten += qMin(bytesToWrite,loadSize); bytesToWrite -= qMin(bytesToWrite,loadSize); progressBar->setMaximum(totalBytes); progressBar->setValue(bytesWritten); statusLabel->setText(tr("已拷贝%1MB").arg(bytesWritten/(1024*1024))); tempBuf.resize(0); qApp->processEvents(); } } rFile->close(); wFile->close(); }//qApp->eventLoop()->processEvents(QEventLoop::ExcludeUserInput); //忽略鼠标键盘事件 //使用定时器: 如果处理可以被安全打断并且随后可以继续执行,这种方法可生效。通过一个特定的“0毫秒定时器” 来实现,只要没有未被处理的事件,这个定时器就会被触发: void Dialog::timerEvent(QTimerEvent *event){ if(event->timerId() == timeId){ while((bytesToWrite > 0) && (!qApp->hasPendingEvents())){ if(isStop){ rFile->close(); wFile->close(); wFile->remove(currentFile); progressBar->setMaximum(totalBytes); progressBar->setValue(0); statusLabel->setText("终止"); saveButton->setEnabled(false); stopButton->setEnabled(false); return ; }else{ tempBuf = rFile->read(qMin(bytesToWrite,loadSize)); wFile->write(tempBuf); bytesWritten += qMin(bytesToWrite,loadSize); bytesToWrite -= qMin(bytesToWrite,loadSize); progressBar->setMaximum(totalBytes); progressBar->setValue(bytesWritten); statusLabel->setText(tr("已拷贝%1MB").arg(bytesWritten/(1024*1024))); tempBuf.resize(0); } } event->accept(); }else{ Dialog::timerEvent(event); } } 如果hasPendingEvents()返回"true",就停止处理并把控制权交给Qt,当Qt处理完它的所有事件,定时器 事件的处理将会继续进行。 //为了使hasPendingEvents()函数正常工作,需设置环境变量“QT_NO_GLIB=1”来避免使用GLib的事件处理函数转载地址:http://wcfei.baihongyu.com/