Qt: 事件过滤器
obj->installEventFilter(filterObject);常常是obj->installEventFilter(this).
发送到obj的所有事件, 都会先发送到filterObject的eventFilter()方法, 即filterObject会过滤obj的事件, 这样就不用为了实现一个事件而要去继承, 再实现一个类, 完成如mouse event, key event等了, 只用在当前类中就可以通过事件过滤来完成.
bool QObject::eventFilter(QObject *watchedObject, QEvent *event) [virtual]
如果是安装者的事件if (obj == watchedObject), 处理过此事件(event->type()), 返回true, 没有处理就返回false.
如果不是安装者的事件, 则把此事件抛给父类去处理:
if (obj == watchedObject) {
处理后返回true, 否则返回false.
} else {
return SuperClass::eventFilter(watchedObject, event);
}
Qt事件处理介绍
- Qt平台会将系统产生的消息转换为Qt事件
- Qt事件是一个QEvent的对象
- Qt事件用来描述程序内部或外部发生的动作
- 任意的QObject对象都具备事件处理的能力
如下图所示,可以看到QEvent的子类非常之多:

比如:
- QInputEvent:用户输入事件
- QDropEvent:用户拖放事件
- QPaintEvent:描述操作系统绘制GUI动作的事件
- QCloseEvent:用户关闭窗口事件
- QTimerEvent:计时器事件
事件处理方式顺序
1.Qt事件产生后立即被分发到QWidget对象
2.QWidget中的event(QEvent*)进行事件处理
3.event()根据事件类型调用不同的事件处理函数
4.在事件处理函数中发送Qt中预定义的信号
5.调用信号关联的槽函数
以按钮点击为例:
1.当点击按钮后,将会触发鼠标事件,调用event(QEvent*)成员函数
3.调用mouseReleaseEvent(QMouseEvent*)成员函数
4.调用click()成员函数
5.触发信号SIGNAL(clicked());
同样,当用户点击窗口的关闭按钮时,也会触发closeEvent()事件函数,该函数需要重写,才能实现
参考示例:

void MainWindow::closeEvent(QCloseEvent *event)
{
if (maybeSave()) //如果还有需要保存的数据
{
writeSettings();
event->accept();
}
else //取消关闭窗口
{
event->ignore();
}
}

类似的还有keyEvent()获取键盘事件函数, keyReleaseEvent()键盘按下事件函数,enterEvent光标进入组件事件函数, leaveEvent光标离开组件事件函数等等。
其中QCloseEvent继承与QEvent,在QEvent中常用成员函数有
void accept (); //接收者处理当前事件 void ignore (); //接收者忽略当前事件,忽略后,事件可能传递给父组件 bool isAccepted(); //判断当前事件是否被处理过
当使用ignore()处理事件时,该事件可能会传递给其父组件对象继续处理
步骤如下:
- 写两个类: QMyWidget、QMyLineEdit(QMyLineEdit是QMyWidget的类成员)
- 通过QMyLineEdit来重写LineEdit的keyReleaseEvent()键盘按下事件函数
- 通过QMyWidget来重写QWidget的keyReleaseEvent()键盘按下事件函数
- 然后通过ignore()处理QMyLineEdit的keyReleaseEvent()事件函数
- 判断是否会继续执行QMyWidget父组件的keyReleaseEvent()事件函数
QLineEdit.h如下所示:

#ifndef QMYLINEEDIT_H
#define QMYLINEEDIT_H
#include <QLineEdit>
#include <QtGui>
class QMyLineEdit : public QLineEdit
{
Q_OBJECT
public:
explicit QMyLineEdit(QWidget *parent = 0);
void keyReleaseEvent( QKeyEvent * event );
};
#endif // QMYLINEEDIT_H

QLineEdit.cpp如下所示:

#include "QMyLineEdit.h"
QMyLineEdit::QMyLineEdit(QWidget *parent) :
QLineEdit(parent)
{
}
void QMyLineEdit::keyReleaseEvent( QKeyEvent * event )
{
qDebug()<<"QMyLineEdit::keyReleaseEvent";
qDebug()<<"key value:"<< event->key();
event->ignore(); //忽略当前事件
}

QMyWidget.h如下所示:

#ifndef QMYWIDGET_H
#define QMYWIDGET_H
#include "QMyLineEdit.h"
#include <QWidget>
class QMyWidget : public QWidget
{
Q_OBJECT
QMyLineEdit line;
public:
explicit QMyWidget(QWidget *parent = 0);
void keyReleaseEvent( QKeyEvent * event );
};
#endif // QMYWIDGET_H

QMyWidget.cpp如下所示:

#include "QMyWidget.h"
QMyWidget::QMyWidget(QWidget *parent) :
QWidget(parent),
line(this)
{
}
void QMyWidget::keyReleaseEvent( QKeyEvent * event )
{
qDebug()<<"QMyWidget::keyReleaseEvent";
qDebug()<<"key value:"<< event->key();
QWidget::keyPressEvent(event);
}

main()函数如下所示:

int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMyWidget w;
w.show();
return a.exec();
}

效果如下:

可以看到成员调用了event->ignore()函数忽略事件后,同样也会继续进入QMyWidget类处理事件
Qt中的事件过滤器
- 事件过滤器可以对需要的组件接收到的事件进行过滤,以及监控
- 任意的QObject对象都可以作为事件过滤器使用
- 事件过滤器的实现,需要重写eventFilter()函数
- 组件要想被监控,则需要通过installEventFilter()安装事件过滤器
- 事件过滤器能够决定是否将事件转发给组件对象,如下图所示:

eventFilter函数体如下所示:
bool QObject::eventFilter ( QObject * watched, QEvent * event );
// watched:代表被监控的组件 event:代表要转发的事件
//返回true,表示该事件也被过滤掉(处理),无需再转发了
//返回false,则正常转发给watched
参考示例-实现文本框只允许输入数字:

class MainWindow : public QMainWindow
{
public:
MainWindow();
protected:
bool eventFilter(QObject *obj, QEvent *ev);
private:
QTextEdit *textEdit;
};
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget(textEdit);
textEdit->setAttribute(Qt::WA_InputMethodEnabled, false); //禁止中文输入法
textEdit->installEventFilter(this);
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
if (obj == textEdit)
{
if (event->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
qDebug() << "Ate key press" << keyEvent->key();
switch(keyEvent->key()) //只接受0~9数字
{
case Qt::Key_0:
case Qt::Key_1:
case Qt::Key_2:
case Qt::Key_3:
case Qt::Key_4:
case Qt::Key_5:
case Qt::Key_6:
case Qt::Key_7:
case Qt::Key_8:
case Qt::Key_9:
return false;
default:
return true;
}
}
else
{
return false;
}
}
else
{
return QMainWindow::eventFilter(obj, event);
}
}

用户拖放事件
每个QWidget对象都能处理拖放事件
常用的拖放事件相关函数有:
void dragEnterEvent ( QDragEnterEvent * event ); //拖事件处理函数 void dropEvent ( QDropEvent * event ) ; //放事件处理函数
拖放事件所处理的数据是QMimeData类
- QMimeData类可以通过QDragEnterEvent 或者 QDropEvent 的成员函数QDropEvent()获取
- QMimeData支持多种不同类型的文件数据
MIME类型常用处理函数如下所示:

拖放事件的步骤如下:
1.在构造函数里通过setAcceptDrops(true)函数,让该组件能接受拖放事件
2.重写dragEnterEvent(QDragEnterEvent* event)函数并判断MIME类型
如果是期待的类型,则调用event ->acceptProposedAction();
否则调用 : event ->ignore();
3.重写dropEvent()函数并判断MIME类型
如果是期待的类型,则获取MIME数据并处理.
否则调用 : event ->ignore();
示例:
头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QMimeData>
class MainWindow : public QMainWindow
{
private:
QTextEdit *textEdit;
void dragEnterEvent(QDragEnterEvent *event);
void dropEvent(QDropEvent *event);
public:
MainWindow();
};
#endif // MAINWINDOW_H

源文件:

#include "mainwindow.h"
MainWindow::MainWindow()
{
textEdit = new QTextEdit;
setCentralWidget(textEdit);
textEdit->setAttribute(Qt::WA_InputMethodEnabled, false) ;
textEdit->setAcceptDrops(false);
setAcceptDrops(true);
}
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
if(event->mimeData()->hasUrls()) //判断拖的类型
{
event->acceptProposedAction();
}
else
{
event->ignore();
}
}
void MainWindow::dropEvent(QDropEvent *event)
{
if(event->mimeData()->hasUrls()) //判断放的类型
{
textEdit->clear();
QList<QUrl> List = event->mimeData()->urls();
for(int i=0;i<List.length();i++)
{
textEdit->insertPlainText(List[i].toLocalFile()+"n");
}
}
else
{
event->ignore();
}
}

由于我们是在MainWindow上处理拖放事件,所以需要设置textEdit->setAcceptDrops()函数为 false,把MainWindow的setAcceptDrops()置为 true,这样我们就能够让MainWindow截获拖放事件,而不是交给QTextEdit处理。
效果:

最后
以上就是忧郁猫咪最近收集整理的关于QT中事件处理、事件过滤器、拖放事件分析的全部内容,更多相关QT中事件处理、事件过滤器、拖放事件分析内容请搜索靠谱客的其他文章。
发表评论 取消回复