Qt:事件处理

来源:互联网 发布:学而知不足 编辑:程序博客网 时间:2024/06/13 11:46
事件是一个从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的事件处理函数



0 0
原创粉丝点击