Introduction to Qt Event Handling
- The Qt platform converts system-generated messages into Qt events
- A Qt event is a QEvent object
- Qt events are used to describe actions that occur inside or outside the program
- Any QObject object has the ability to handle events
The common event inheritance diagram of Qt is as follows:
- QInputEvent: user input event
- QDropEvent: User drag and drop event
- QPaintEvent: events that describe the GUI drawing action of the operating system
- QCloseEvent: user closes the window event
- QTimerEvent: timer event
order of events
1. The Qt event is dispatched to the QWidget object immediately after it is generated
2. Event (QEvent*) in QWidget for event processing
3.event() calls different event handlers according to the event type
4. Send a predefined signal in Qt in the event handler
5. Call the slot function associated with the signal
Take button click as an example, as shown in the following figure:
QPushButton event handling summary
1. When the button is clicked, the mouse event will be triggered
2. Call the event(QEvent*) member function
3. Call the mouseReleaseEvent(QMouseEvent*) member function
4. Call the click() member function
5. Trigger signal SIGNAL(clicked()) ;
Similarly, when the user clicks the close button of the window, the closeEvent() event function will also be triggered, which needs to be rewritten to achieve
Reference example:
void MainWindow::closeEvent(QCloseEvent *event) { if (maybeSave()) // If there is still data to save
{ writeSettings(); event->accept(); }
else // Cancel closing the window { event->ignore(); } }
Similar to keyEvent() to get keyboard event function, keyReleaseEvent() to keyboard press event function, enterEvent cursor to enter component event function, leaveEvent cursor to leave component event function and so on.
Among them, QCloseEvent inherits from QEvent, and the commonly used member functions in QEvent are
void accept (); // The receiver handles the current event void ignore (); // The receiver ignores the current event, after ignoring, the event may be passed to the parent component bool isAccepted(); // Determine whether the current event has been processed
When using ignore() to handle an event, the event may be passed to its parent component object to continue processing
Proceed as follows:
- Write two classes: QMyWidget, QMyLineEdit (QMyLineEdit is a class member of QMyWidget)
- Rewrite LineEdit's keyReleaseEvent() keyboard press event function through QMyLineEdit
- Rewrite QWidget's keyReleaseEvent() keyboard press event function through QMyWidget
- Then handle the keyReleaseEvent() event function of QMyLineEdit through ignore()
- Determine whether the keyReleaseEvent() event function of the parent component of QMyWidget will continue to be executed
QLineEdit.h looks like this:
#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(); } }
效果: