• 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()+"
    ");
            }
        }
        else
        {
              event->ignore();
        }
    }

    效果:

     

  • 相关阅读:
    Yii Framework 开发教程: 总结
    code first 如何创建索引字段
    Entity Framework 使用 Left Join
    如何查看IIS并发连接数
    c# List<int> 转 string 以及 string [] 转 List<int>
    linq中如何在join中指定多个条件
    关于学习的感悟
    c# 的访问修饰符是private 还是 internal?
    C# 与 .Net 3.5 高级程序设计(第四版) 读书笔记(一)
    解决Excel 提示向程序发送命令时出现错误
  • 原文地址:https://www.cnblogs.com/lifexy/p/8996425.html
Copyright © 2020-2023  润新知