17.QT-事件处理分析、事件过滤器、拖放事件

Qt事件处理介绍

  • Qt平台会将系统产生的消息转换为Qt事件
  • Qt事件是一个QEvent的对象
  • Qt事件用来描述程序内部或外部发生的动作
  • 任意的QObject对象都具备事件处理的能力

Qt常见的事件继承图如下:

  • QInputEvent:用户输入事件
  • QDropEvent:用户拖放事件
  • QPaintEvent:描述操作系统绘制GUI动作的事件
  • QCloseEvent:用户关闭窗口事件
  • QTimerEvent:计时器事件

事件处理方式顺序

1.Qt事件产生后立即被分发到QWidget对象

2.QWidget中的event(QEvent*)进行事件处理

3.event()根据事件类型调用不同的事件处理函数

4.在事件处理函数中发送Qt中预定义的信号

5.调用信号关联的槽函数

以按钮点击为例,如下图所示:

QPushButton事件处理总结

1.当点击按钮后,将会触发鼠标事件

2.调用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类

MIME类型常用处理函数如下所示:

拖放事件的步骤如下:

1.在构造函数里通过setAcceptDrops(true)函数,让该组件能接受拖放事件

2.重写dragEnterEvent(QDragEnterEvent* event)函数并判断MIME类型

  如果是期待的类型,则调用event ->acceptProposedAction();

  否则调用 : event ->ignore();

3.重写dropEvent()函数并判断MIME类型

  如果是期待的类型,则获取MIME数据并处理.

  否则调用 : event ->ignore();

示例:

 class MainWindow : public QMainWindow
 {
private:
    QTextEdit *textEdit;
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);

public:
    MainWindow();
 };

 MainWindow::MainWindow()
 {
     textEdit = new QTextEdit;
     setCentralWidget(textEdit);
     textEdit->setAttribute(Qt::WA_InputMethodEnabled, false) ;
     textEdit->installEventFilter(this);
     this->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();
    }
}

效果:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Go语言-base64使用

什么是base64? Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045~RFC2049,上面有MIME的详细规范。...

465130
来自专栏玄魂工作室

如何将HTML字符转换为DOM节点并动态添加到文档中

将字符串动态转换为DOM节点,在开发中经常遇到,尤其在模板引擎中更是不可或缺的技术。 字符串转换为DOM节点本身并不难,本篇文章主要涉及两个主题:<br />

19520
来自专栏用户2442861的专栏

PyQt4 - 关闭最小化问题

在这个部分,我们开始学习一些PyQt4的基本功能,解释会比较详细,就像教孩子说话一样。 最简单的example     下面的示例会非常的简单,仅仅显示...

35710
来自专栏24K纯开源

Qt界面编程:窗口传值方式

1、问题   一个这样的场景:主窗口界面有一个菜单项,点击该菜单项弹出一个对话框。点击对话框上的测试按钮,显示主窗口类中的一个字符串成员的内容。这就是整个窗口传...

41170
来自专栏小狼的世界

使用YUI3创建Popup弹出层

很多互联网的项目应用中,弹出层出现的越来越多,使用YUI3可以快速的实现制作弹出层的效果。

9510
来自专栏思考的代码世界

Python网络数据采集之HTML解析|第01天

假如我们确定一个我们需要采集的目标信息,可能是一组统计数据、或者一个 title等,但是此时这个目标可能藏的比较深,可能在第20层的标签里面,你可能会用下面的方...

19440
来自专栏静晴轩

你所不知道的setTimeout

JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成。它们向任务队列...

496120
来自专栏逍遥剑客的游戏开发

C++与Flash的交互

38180
来自专栏码洞

会玩Go!会玩Python!嘭!Go-Python!

Golang是静态语言,性能很好,当它不那么灵活,不好在运行时动态运行代码。Python是动态语言,非常灵活,但是性能很差。古人云:“鱼和熊掌不能兼得”。但是如...

41910
来自专栏ascii0x03的安全笔记

PySide——Python图形化界面入门教程(一)

PySide——Python图形化界面入门教程(一) ——基本部件和HelloWorld 翻译自:http://pythoncentral.io/intro-...

74680

扫码关注云+社区

领取腾讯云代金券