1. 程式人生 > >17.QT-事件處理分析、事件過濾器、拖放事件

17.QT-事件處理分析、事件過濾器、拖放事件

期待 使用 lis 相關 事件處理 [] 支持 實現 endif

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類

  • QMimeData類可以通過QDragEnterEvent 或者 QDropEvent 的成員函數QDropEvent()獲取
  • 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();
    }
}

效果:

技術分享圖片

17.QT-事件處理分析、事件過濾器、拖放事件