一、事件处理
1.理论:
事件由窗口系统或系统自身产生,用以响应各种行为或情况。如当按下鼠标或释放鼠标时,
会产生鼠标事件,按下键盘时,出现按键事件…(详见QEvent帮助文档介绍)
QT基于事件、信号与槽来保证界面的正常工作,信号与槽完成对象之间的通信,
而系统底层产生的所有事件,比如上面提到的键盘按下、松开,鼠标左键、滚轮等,
都会由QT采集并做封装,放到QT的事件队列中。而QT的主循环(即main.cpp里的a.exec())
功能即是从事件队列中按照顺序取出每一个事件并做处理。
2.处理过程:
将事件从队列中取出,封装成 QEvent 并交给相应类的 event() 方法处理。
event()方法会根据事件类型e->type(),把QEvent类封装成更精确的事件类。
比如QKeyEvent、QMouseEvent等,事件类详见enum QEvent::Type帮助文档。
然后调用更加精准的处理方法处理相应的事件类。
比如QKeyEvent会分别被QWidget::keyPressEvent()、QWidget::keyReleaseEvent()
等方法进行处理。以上提到的方法都是虚方法,子类可进行重写。
3.编程要点:
a.重写精准的事件方法,比如keyPressEvent() (推荐)
过滤所需要的键值,做业务逻辑处理
不需要的键值,交由父类做默认处理(调用父类的keyPressEvent()方法)
b.重写总的处理方法event()
首先通过e->type()过滤出要处理的事件类型
通过强转将事件转换为精准事件
做业务逻辑处理
不需要处理的事件交个父类的event()去处理
4.组件重写方法:
新建一个类,继承自要重写的组件类,重新实现某些方法或者重新定义某些属性。
实例:界面中添加一个单行输入框,当输入字符为某些特殊字符时候,提示用户并禁止输入。
(掌握qt designer的组件提升方法)
提示小技巧:QToolTip::showText(this->mapToGlobal(this->pos()), “不能使用特殊字符”, this);
组件提升方法:
从组件列表找一个最相近的组件,拖到界面中,右键组件点击“提升为…”
输入提升的类名称(粘贴复制),勾选全局包含选项。点击提升即可。
#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H
#include <QtWidgets>
class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit MyLineEdit(QWidget *parent = 0);
signals:
public slots:
protected:
//virtual void keyPressEvent(QKeyEvent * event);
virtual bool event(QEvent * event) ;
};
#endif // MYLINEEDIT_H
#include "mylineedit.h"
MyLineEdit::MyLineEdit(QWidget *parent) :
QLineEdit(parent)
{
this->setStyleSheet("color:red");
}
#if 0
void MyLineEdit::keyPressEvent(QKeyEvent *event)
{
//qDebug("0x%x", event->key()); //可以通过此方法快速找到按键键值
//过滤特殊按键,比如"/"
if(event->key() == Qt::Key_Slash){
QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);
}else{ //其它按键,交由父类的方法去处理
QLineEdit::keyPressEvent(event);
}
}
#else
bool MyLineEdit::event(QEvent *event)
{
//过滤所需要的事件类
if(event->type() == QEvent::KeyPress){ //过滤按键按下事件
//把原始事件对象QEvent转化为QKeyEvent对象
QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(event);
//过滤具体的按键
if(keyEvent->key() == Qt::Key_Slash){
QToolTip::showText(this->mapToGlobal(this->pos()), "不能使用特殊字符", this);
}else{ //其它按键,交由父类的方法去处理
QLineEdit::keyPressEvent(keyEvent);
}
}else{ //其它类的事件
QLineEdit::event(event); //不需要处理的事件,交给父类原方法
}
}
#endif
5.安装过滤器过滤事件
bool QObject::eventFilter(QObject * watched, QEvent * event) [virtual]
安装过滤器可不用重新重写类即可完成事件过滤,详见帮助文档中demo
#ifndef FILTERWIG_H
#define FILTERWIG_H
#include <QtWidgets>
namespace Ui {
class FilterWig;
}
class FilterWig : public QMainWindow
{
Q_OBJECT
public:
explicit FilterWig(QWidget *parent = 0);
~FilterWig();
private:
Ui::FilterWig *ui;
protected:
bool eventFilter(QObject *obj, QEvent *ev);
};
#endif // FILTERWIG_H
#include "filterwig.h"
#include "ui_filterwig.h"
FilterWig::FilterWig(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::FilterWig)
{
ui->setupUi(this);
ui->lineEdit->installEventFilter(this);
}
FilterWig::~FilterWig()
{
delete ui;
}
/**
* @brief 事件过滤方法,会在事件处理源头首先调用
* @param obj 事件的源头(对象)
* @param event 事件本身
* @return true:代表过滤器已经做完所有处理,不需要继续处理
* false:只处理一部分,需要继续处理
*/
bool FilterWig::eventFilter(QObject *obj, QEvent *event)
{
//只处理lineEdit的事件过滤
if (obj == ui->lineEdit) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
if(keyEvent->key() == Qt::Key_Slash){
qDebug()<<"/ key";
return true; //对于"/"按键处理到此为止
}else{
return false; //其它按键需要继续处理
}
} else {
return false;
}
} else {
// pass the event on to the parent class
return QMainWindow::eventFilter(obj, event);
}
}
#include "filterwig.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
FilterWig w;
w.show();
return a.exec();
}