9.事件处理

一、事件处理
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();
}
发布了10 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_40083589/article/details/94026081
今日推荐