QT-qevent 事件的accept()和ignore()
QEvent的accept()和ignore()一般不會(huì)用到,因?yàn)椴蝗缰苯诱{(diào)用QWidget類的事件處理函數(shù)直接,而且作用是一樣的,見(jiàn)下面的例子。
推薦直接調(diào)用QWidget的事件處理函數(shù)。而不是調(diào)用accept()和ignore()。
只有一種情況下,必須使用調(diào)用accept()和ignore(),那就是closeEvent(),在closeEvent()的事件處理函數(shù)中,必須調(diào)用accept()和ignore()。即如果想窗口被關(guān)閉,那么必須顯示調(diào)用event->accept();如果不想關(guān)閉窗口,必須顯示調(diào)用ignore(),否則窗口默認(rèn)會(huì)關(guān)閉。
本章內(nèi)容也是關(guān)于Qt事件。或許這一章不能有一個(gè)完整的例子,因?yàn)閷?duì)于事件總是感覺(jué)很抽象,還是從底層上理解一下比較好的吧!
前面說(shuō)到了事件的作用,下面來(lái)看看我們?nèi)绾蝸?lái)接收事件。回憶一下前面的代碼,我們?cè)谧宇愔兄貙懥耸录瘮?shù),以便讓這些子類按照我們的需要完成某些功能,就像下面的代碼:
?void?MyLabel::mousePressEvent(QMouseEvent *?event)
{
?????????if(?event->button() == Qt::LeftButton) {
?????????????????// do something
????????}?else?{
????????????????QLabel::mousePressEvent(?event);
????????}
}
上面的代碼和前面類似,在鼠標(biāo)按下的事件中檢測(cè),如果按下的是左鍵,做我們的處理工作,如果不是左鍵,則調(diào)用父類的函數(shù)。這在某種程度上說(shuō),是把事件向上傳遞給父類去響應(yīng),也就是說(shuō),我們?cè)谧宇愔小昂雎浴绷诉@個(gè)事件。
比如上面的例子,eventLabel忽略了這個(gè)事件,那么這個(gè)事件就會(huì)被繼續(xù)傳遞下去,實(shí)際上是傳遞給了eventLabel的父組件,QLabel,
accept()接收,表面eventLabel會(huì)處理這個(gè)事件,那么這個(gè)事件就不會(huì)再繼續(xù)傳遞下去,那么QLabel就不會(huì)再收到這個(gè)事件,
我們可以把Qt的事件傳遞看成鏈狀:如果子類沒(méi)有處理這個(gè)事件,就會(huì)繼續(xù)向其他類傳遞。
其實(shí),Qt的事件對(duì)象都有一個(gè)accept()函數(shù)和ignore()函數(shù)。正如它們的名字,前者用來(lái)告訴Qt,事件處理函數(shù)“接收”了這個(gè)事件,不要再傳遞;后者則告訴Qt,事件處理函數(shù)“忽略”了這個(gè)事件,需要繼續(xù)傳遞,尋找另外的接受者。在事件處理函數(shù)中,可以使用isAccepted()來(lái)查詢這個(gè)事件是不是已經(jīng)被接收了。
事實(shí)上,我們很少使用accept()和ignore()函數(shù),而是想上面的示例一樣,如果希望忽略事件,只要調(diào)用父類的響應(yīng)函數(shù)即可。(其實(shí)作用是一樣的)
為什么要這么做呢?因?yàn)槲覀儫o(wú)法確認(rèn)父類中的這個(gè)處理函數(shù)沒(méi)有操作,如果我們?cè)谧宇愔兄苯雍雎允录?#xff0c;Qt不會(huì)再去尋找其他的接受者,那么父類的操作也就不能進(jìn)行,這可能會(huì)有潛在的危險(xiǎn)。
另外我們查看一下QWidget的mousePressEvent()函數(shù)的實(shí)現(xiàn):
?void?QWidget::mousePressEvent(QMouseEvent *?event)
{
?????????event->ignore();//QWidget 會(huì)忽略這個(gè)事件,
?????????if?((windowType() == Qt::Popup)) {
?????????????????event->accept();
????????????????QWidget* w;
?????????????????while?((w = qApp->activePopupWidget()) && w !=?this){
????????????????????????w->close();
?????????????????????????if?(qApp->activePopupWidget() == w)?// widget does not want to dissappear
????????????????????????????????w->hide();?// hide at least
????????????????}
?????????????????if?(!rect().contains(?event->pos())){
????????????????????????close();
????????????????}
????????}
}
請(qǐng)注意第一條語(yǔ)句,如果所有子類(比如EventLabel類,)都沒(méi)有重寫mousePressEvent函數(shù),這個(gè)事件會(huì)在這里被忽略掉,這暗示著這個(gè)組件(eventLabel)不關(guān)心這個(gè)事件,這個(gè)事件就可能被傳遞給其父組件。
不過(guò),事情也不是絕對(duì)的。在一個(gè)情形下,我們必須使用accept()和ignore()函數(shù),那就是在窗口關(guān)閉的時(shí)候。這個(gè)必須明確顯示的調(diào)用accept()和ignore(),
在closeEvent()事件處理函數(shù)中,accept()是關(guān)閉窗口,ignore()是不關(guān)閉窗口,只有在closeEvent()中才是這樣,
如果你在窗口關(guān)閉時(shí)需要有個(gè)詢問(wèn)對(duì)話框,那么就需要這么去寫:
closeEvent事件的默認(rèn)槽函數(shù)是QWidget類的CloseEvent()函數(shù),該函數(shù)中,會(huì)關(guān)閉掉當(dāng)前的widget,
?void?MainWindow::closeEvent(QCloseEvent *?event)
{
?????????if(continueToClose()) {
?????????????????event?->accept();
????????}?else?{
?????????????????event->ignore();
????????}
}
bool?MainWindow::continueToClose()
{
?????????if(QMessageBox::question(?this,
??????????????????????????????????????????? tr(?"Quit"),
??????????????????????????????????????????? tr(?"Are you sure to quit this application?"),
??????????????????????????????????????????? QMessageBox::Yes | QMessageBox::No,
??????????????????????????????????????????? QMessageBox::No)
????????????????== QMessageBox::Yes) {
?????????????????return?true;
????????}?else?{
?????????????????return?false;
????????}
}
這樣,我們經(jīng)過(guò)詢問(wèn)之后才能正常退出程序。
/*****************Qt中QEvent的accept和ignore函數(shù) 事件詳解(以QLabel事件重載為例)
Qt中QEvent的accept和ignore函數(shù)
QApplication::notify() (用來(lái)發(fā)送一個(gè)事件)
QObject::eventFilter() (用來(lái)過(guò)濾事件,即接收攔截別的對(duì)象的事件,并處理)
QObject::event() (接收發(fā)送給自己這個(gè)對(duì)象的事件)
Qt事件相關(guān)函數(shù)的兩種通信方式:1、通過(guò)返回值;2、通過(guò)accept和ignore
在Qt事件傳遞和接收相關(guān)的函數(shù)中,QApplication::notify() , QObject::eventFilter() , QObject::event() 返回值都是bool類型的,返回值為bool類型的函數(shù),通過(guò)返回值來(lái)說(shuō)明事件是否被識(shí)別(用Qt Assistant中的話叫recognized,深層含義是event()函數(shù)對(duì)事件進(jìn)行和處理,或調(diào)用了特定事件處理函數(shù)進(jìn)行了處理);而特定的事件處理函數(shù)例如mousePressEvent(), keyPressEvent(), paintEvent()等函數(shù)它們都是在event()函數(shù)中通過(guò)switch...case調(diào)用的,返回值都是void,處在事件循環(huán)隊(duì)列的最末端,一般由這些函數(shù)調(diào)用accept()函數(shù)和ignore()函數(shù)來(lái)表明事件是否被接受。下面講解這兩種通信方式的區(qū)別和用途。
? ? accept()函數(shù)和ignore()函數(shù)用來(lái)設(shè)置事件的accept屬性,決定此事件會(huì)不會(huì)轉(zhuǎn)發(fā)給父對(duì)象;返回值為true和false決定的是同一目標(biāo)對(duì)象的下一個(gè)處理函數(shù)是否會(huì)被調(diào)用,由于事件循環(huán)及傳遞過(guò)程是個(gè)非常復(fù)雜的過(guò)程,至少有20層函數(shù)調(diào)用,我們可以將它簡(jiǎn)化為維護(hù)事件循環(huán)隊(duì)列的exec()函數(shù),針對(duì)某一目標(biāo)對(duì)象的processXX()函數(shù),各個(gè)的事件處理函數(shù)假設(shè)只有2個(gè)eventFilter()函數(shù),event()函數(shù)。其中processXX()函數(shù),負(fù)責(zé)傳遞事件到某一特定的對(duì)象,我們可以簡(jiǎn)單的理解為在它的函數(shù)體中首先調(diào)用了eventFilter()事件過(guò)濾器函數(shù),如果eventFilter返回值為true,則不再調(diào)用下一個(gè)處理函數(shù)event(),否則接著調(diào)用event()函數(shù),event()函數(shù)返回true和false已經(jīng)沒(méi)有意義了,因?yàn)槲覀兗僭O(shè)它是最后一個(gè)事件處理函數(shù)了,這就是返回值的用處(這也很容易理解,假如在eventFilter()函數(shù)中調(diào)用了ignore(),并且返回false,那么event()函數(shù)將被緊接著調(diào)用,且它收到的事件accept屬性為false);到這里我們捏造的processXX函數(shù)返回,根據(jù)其傳出的事件的accpet屬性來(lái)決定是否傳遞給父對(duì)象,如果為accpet為false,則傳遞給父對(duì)象嗎,在傳遞給父對(duì)象前,將accept屬性重置為true。
總結(jié):accpet屬性對(duì)應(yīng)的accpet()函數(shù)和ignore()函數(shù)決定的事件傳遞是在父子對(duì)象之間的,而返回值決定的事件傳遞是在同一目標(biāo)對(duì)象的各個(gè)事件處理函數(shù)之間的。在各個(gè)事件處理函數(shù)中都可以調(diào)用ignore()和accept(),以最后一個(gè)調(diào)用這兩個(gè)函數(shù)的事件處理函數(shù)設(shè)置的accept屬性值為最終值。
驗(yàn)證:
設(shè)計(jì)如下界面,其中press為類型為自定義的MyLabel,繼承于QLabel
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
?
mylabel.cpp文件
#include "mylabel.h"
#include <QDebug>
#include <QMouseEvent>
?
MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
?
}
?
void MyLabel::mousePressEvent(QMouseEvent *ev)
{
? ? if(ev->type() == QEvent::MouseButtonPress)
? ? ? ? qDebug() << "in Mylabel class press";
}
?
void MyLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
? ? qDebug() << "in MyLabel class mouse DoubleClickEvent" << "event ignore " << !event->isAccepted();
?
? ? QLabel::mouseDoubleClickEvent(event);
}
其中重載了mousePressEvent()和mouseDoubleEvent();
mainwindow.cpp文件:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMouseEvent>
#include <QEvent>
#include <QDebug>
?
MainWindow::MainWindow(QWidget *parent) :
? ? QMainWindow(parent),
? ? ui(new Ui::MainWindow)
{
? ? ui->setupUi(this);
? ? ui->label->installEventFilter(this);
}
?
MainWindow::~MainWindow()
{
? ? delete ui;
}
?
void MainWindow::mousePressEvent(QMouseEvent */*event*/)
{
? ? qDebug() << "in MainWindow class press";
}
void MainWindow::mouseDoubleClickEvent(QMouseEvent *event)
{
? ? qDebug() << "in MainWindow class DoubleClick";
}
?
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
? ? if(watched == ui->label)
? ? {
? ? ? ? if(event->type() == QEvent::MouseButtonPress)
? ? ? ? {
? ? ? ? ? ? qDebug() << "in MainWindow eventFilter press";
? ? ? ? ? ? event->ignore();
? ? ? ? ? ? return true;
? ? ? ? }
? ? ? ? event->ignore();
? ? ? ? return false;
? ? }
? ? else
? ? {
? ? ? ? return QMainWindow::eventFilter(watched, event);
? ? }
}
其中MyLabel類的label對(duì)象,安裝了主窗口的事件過(guò)濾器,關(guān)鍵的驗(yàn)證代碼,在于事件過(guò)濾器,事件過(guò)濾器過(guò)濾了MouseButtonPress事件,按照上述我們所說(shuō)的邏輯,當(dāng)我們單機(jī)界面的press圖標(biāo),過(guò)濾器MainWindow::eventFilter()先被調(diào)用,然后事件會(huì)傳遞給父對(duì)象,調(diào)用MainWindow::mousePressEvent(),因?yàn)樵O(shè)置過(guò)濾器中調(diào)用了了event->ignore(),但子對(duì)象label接收不到事件,因?yàn)榉祷亓藅rue,所以控制臺(tái)只輸出了兩句話:
in MainWindow eventFilter press
in MainWindow class press
當(dāng)雙擊press圖標(biāo),會(huì)觸發(fā)一次MousePressEvent,然后觸發(fā)DoubleClickEvent,MousePressEvent和上述單機(jī)過(guò)程相同,DoubleClickEvent,事件在過(guò)濾器中執(zhí)行了event->ingore();return false;所以執(zhí)行完過(guò)濾器,傳遞給目標(biāo)對(duì)象再執(zhí)行Mylabel::mouseDoubleClick(),且此函數(shù)接收到的事件accpet屬性為false,然后傳遞為父對(duì)象,執(zhí)行MainWindow::mouseDoubleClick(),所以要有4句話輸出:
in MainWindow eventFilter press
in MainWindow class press
in MyLabel class mouse DoubleClickEvent event ignore ?true
in MainWindow class DoubleClick
下面我們參考Qt中QWidget和QAbstractButton的源碼來(lái)理解accept()和ignore()函數(shù):
參考Qt中QWidget類的源碼,許多事件處理函數(shù)都直接調(diào)用ignore函數(shù)來(lái)促使事件傳遞給父對(duì)象,因?yàn)镼Widget作為窗口部件的基類,無(wú)需對(duì)這些事件做出響應(yīng),只能拋給父類處理:
QWidget類部分源碼:
void QWidget::mouseMoveEvent(QMouseEvent *event)
{
? ? event->ignore();
}
void QWidget::mouseReleaseEvent(QMouseEvent *event)
{
? ? event->ignore();
}
void QWidget::tabletEvent(QTabletEvent *event)
{
? ? event->ignore();
}
但對(duì)于QPushButton類的基類QAbstractButton,它就必須對(duì)鼠標(biāo)事件進(jìn)行處理。查看其鼠標(biāo)松開事件處理函數(shù),它的處理步驟是如果按鍵是按下的狀態(tài),并且松開事件的坐標(biāo)在按鍵區(qū)域內(nèi),則調(diào)用d->click()函數(shù),發(fā)出clicked()信號(hào),并accept該事件,對(duì)于其他情況仍然需要ignore事件,促使事件繼續(xù)傳遞:
QAbstractButton部分源碼:
void QAbstractButton::mouseReleaseEvent(QMouseEvent *e)
{
? ? Q_D(QAbstractButton);
? ? d->pressed = false;
?
? ? if (e->button() != Qt::LeftButton) {
? ? ? ? e->ignore();
? ? ? ? return;
? ? }
? ? //檢測(cè)mouseReleaseEvent發(fā)生之前,按鍵是否是按下狀態(tài)
? ? if (!d->down) {
? ? ? ? // refresh is required by QMacStyle to resume the default button animation
? ? ? ? d->refresh();
? ? ? ? e->ignore();
? ? ? ? return;
? ? }
? ? //檢測(cè)mouseReleaseEvent事件發(fā)生時(shí),坐標(biāo)是否在按鍵區(qū)域內(nèi)
? ? if (hitButton(e->pos())) {
? ? ? ? d->repeatTimer.stop();
? ? ? ? d->click();
? ? ? ? e->accept();//accept該事件,停止對(duì)事件的轉(zhuǎn)發(fā)
? ? } else {
? ? ? ? setDown(false);
? ? ? ? e->ignore();
? ? }
}
如果事件在某個(gè)對(duì)象的事件處理函數(shù)中被ignore,即標(biāo)記為未處理,則該事件將會(huì)被傳遞給該對(duì)象的父對(duì)象,直到事件被處理或者到達(dá)最頂層對(duì)象,每次事件被event()函數(shù)、xxxEvent()(特定事件處理函數(shù))接收到時(shí),事件的accept屬性都已經(jīng)在傳入之前被重置為true,即在event()、特定事件處理函數(shù)中可以省略對(duì)accept()函數(shù)的調(diào)用,下面這個(gè)例子自定義一個(gè)MyLabel的類,并在自定義的Widget中插入MyLabel標(biāo)簽,我們可以通過(guò)mousePressEvent事件來(lái)查看此事件是如何在子對(duì)象和父對(duì)象之間傳遞的。
mylabel.cpp文件
#include "mylabel.h"
#include <QLabel>
#include <QMessageBox>
#include <QMouseEvent>
#include <QDebug>
?
MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
? ? //設(shè)置QLabel類默認(rèn)追蹤鼠標(biāo)軌跡,默認(rèn)不追蹤,重載mouseMoveEvent()時(shí)可以設(shè)置此屬性,否則只有先點(diǎn)擊一下MyLabel標(biāo)簽,才能開始接收鼠標(biāo)相關(guān)事件
? ? //this->setMouseTracking(true);
}
void MyLabel::mousePressEvent(QMouseEvent *event)
{
? ? qDebug() << "in MyLabel::mousePressEvent" << event->isAccepted();
? ? QMessageBox::information(this, "MyLabel",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?QString("coordinate is %1 %2").arg(event->globalPos().x()).arg(event->globalPos().y()));
? ? event->ignore();
}
MyLabel繼承自QLabel,只是對(duì)父類中mousePressEvent函數(shù)進(jìn)行了簡(jiǎn)單的重載,并且在處理完事件后,調(diào)用了ignore()函數(shù),這回導(dǎo)致mousePressEvent事件繼續(xù)傳遞下去。
widget.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QCloseEvent>
#include <QDebug>
#include <QPushButton>
?
Widget::Widget(QWidget *parent) :
? ? QWidget(parent),
? ? ui(new Ui::Widget)
{
? ? ui->setupUi(this);
}
?
Widget::~Widget()
{
? ? delete ui;
}
?
void Widget::mousePressEvent(QMouseEvent *event)
{
? ? qDebug() << "in Widget::mousePressEvent " <<event->isAccepted();
? ? QMessageBox::information(this, "Widget",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?QString("coordinate is %1 %2").arg(event->globalPos().x()).arg(event->globalPos().y()));
}
?
bool Widget::event(QEvent *event)
{
? ? if(event->type() == QEvent::MouseButtonPress)
? ? {
? ? ? ? qDebug() << "in Widget::event" << event->isAccepted() << "event type is " << event->type();
? ? }
? ? return QWidget::event(event);
}
Widget類中重載了mousePressEvent函數(shù)和event函數(shù),用來(lái)驗(yàn)證mousePressEvent事件是否會(huì)傳遞到父對(duì)象中,運(yùn)行效果是點(diǎn)擊MyLabel圖標(biāo),會(huì)彈出一個(gè)MessageBox,點(diǎn)擊確定后,彈出第二個(gè)MessageBox;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
?
另外Widget::event()函數(shù)中的提示會(huì)在Widget::mousePressEvent()函數(shù)中提示顯示之前顯示,但在MyLabel::mousePressEvent()函數(shù)中提示顯示后顯示,如下:
in MyLabel::mousePressEvent true
in Widget::event true event type is ?QEvent::Type(MouseButtonPress)
in Widget::mousePressEvent ?true
這說(shuō)明,事件的傳遞順序是先傳遞到子對(duì)象的event(),子對(duì)象的event()調(diào)用子對(duì)象的mousePressEvent()函數(shù),然后事件傳遞到父對(duì)象的event()函數(shù),然后調(diào)用父對(duì)象的mousePressEvent()函數(shù)。
向widget.cpp文件中添加如下代碼:
void Widget::closeEvent(QCloseEvent *event)
{
? ? qDebug() << "in Widget::closeEvent" << event->isAccepted();
? ? int result = QMessageBox::warning(this, "warning","are you sure to close?", QMessageBox::Ok | QMessageBox::Cancel);
? ? if(result == QMessageBox::Ok)
? ? ? ? //注意此處的accept()函數(shù)可以省略,因?yàn)閑vent在進(jìn)入此函數(shù)前,accept屬性已經(jīng)置為true
? ? ? ? ;//event->accept();
? ? else
? ? ? ? event->ignore();
}
重載closeEvent可以實(shí)現(xiàn)關(guān)閉窗口前詢問(wèn)是否關(guān)閉,注意,自定義關(guān)閉按鍵時(shí),connect()函數(shù)參數(shù)設(shè)置如下:
connect(ui->closeButton, &QPushButton::clicked, this, &Widget::close);
如何寫成如下,則不能實(shí)現(xiàn)上述功能,除非子類化QApplication,然后重載quit()函數(shù):
connect(ui->closeButton, &QPushButton::clicked, qApp, &QApplication::quit);
關(guān)閉窗口時(shí),從點(diǎn)擊關(guān)閉按鈕,到相應(yīng)窗口關(guān)閉事件,事件傳遞函數(shù)的調(diào)用流程:
exec()中的processEvent()從事件循環(huán)中收到mouseReleaseEvent事件(目標(biāo)對(duì)象為關(guān)閉按鈕),通過(guò)notify()等20幾層函數(shù)調(diào)用最終到達(dá)目標(biāo)對(duì)象的mousePress()函數(shù),這里會(huì)發(fā)出clicked()信號(hào),發(fā)送clicked()信號(hào)后,mousePress()函數(shù)等待窗口的槽函數(shù)close()調(diào)用完畢,槽函數(shù)close()中調(diào)用sendPost()函數(shù),發(fā)送closeEvent事件,到窗口對(duì)象,并等待返回結(jié)果,其中又經(jīng)過(guò)notify()等很多層函數(shù)調(diào)用,最終到達(dá)窗口的closeEvent()處理函數(shù),處理完成后再逐級(jí)返回,當(dāng)返回到close()槽函數(shù)(close()函數(shù)又調(diào)用了close_helper()函數(shù))時(shí),會(huì)根據(jù)事件的accept屬性,決定窗口是否關(guān)閉,close_helper()函數(shù)的部分源碼:
?if (mode == CloseWithSpontaneousEvent)
? ? ? ? ? ? QApplication::sendSpontaneousEvent(q, &e);
? ? ? ? else
? ? ? ? ? ? QApplication::sendEvent(q, &e);
? ? ? ? if (!that.isNull() && !e.isAccepted()) {
? ? ? ? ? ? data.is_closing = 0;
? ? ? ? ? ? return false;
close()函數(shù)運(yùn)行完畢后,關(guān)閉按鍵的mousePress()函數(shù)也開始返回,經(jīng)過(guò)20多層返回最終返回到exec()函數(shù)(這里是窗口放棄關(guān)閉的情況)。可以發(fā)現(xiàn)整個(gè)過(guò)程都是在串行的執(zhí)行,不管是傳遞事件,還是信號(hào)調(diào)用槽函數(shù),都會(huì)等待后續(xù)處理結(jié)果,最終都會(huì)返回到exec()事件循環(huán)中去,所以我們可以將每次調(diào)用processEvent()之后的過(guò)程都看成簡(jiǎn)單的函數(shù)相互調(diào)用,包括信號(hào)和槽的調(diào)用,sendEvent()傳遞事件,都可以看成簡(jiǎn)單的函數(shù)調(diào)用,因?yàn)槲覀冎婚_了一個(gè)線程。
所以事件循環(huán)的簡(jiǎn)單模型可以描述為Qt程序在while循環(huán)中一直調(diào)用processEvent()函數(shù),processEvent()函數(shù)會(huì)處理事件并刪除,所以事件循環(huán)隊(duì)列會(huì)減少,但在處理事件的過(guò)程中Qt程序可能調(diào)用postEvent()函數(shù)添加新的事件到事件循環(huán)隊(duì)列中去,同時(shí)操作系統(tǒng)也會(huì)添加事件到事件循環(huán)隊(duì)列中去,所以程序才能一直響應(yīng)用戶請(qǐng)求,sendEvent()函數(shù)不添加事件到隊(duì)列中去,但是它可以看成是應(yīng)用程序處理當(dāng)前事件的延長(zhǎng),即在本次processEvent()調(diào)用中插入了一個(gè)事件,處理完插入的事件,才能繼續(xù)返回處理本次processEvent()調(diào)用要處理的本來(lái)事件,并最終又回到事件循環(huán)隊(duì)列中去,而不用像postEvent()那樣,將傳遞的事件放到以后的processEvent()函數(shù)調(diào)用中去處理。所以sendEvent()可以看成傳遞的事件被立即處理(同步),postEvent()不能掌控它所傳遞事件到底什么時(shí)候被處理,因?yàn)樗恢朗录h(huán)隊(duì)列中排在它所傳遞的事件之前還有多少個(gè)事件(異步)。
?
可以參考http://blog.csdn.net/xiaoyink/article/details/79404377
下面我說(shuō)一個(gè)例子(曾經(jīng)參與過(guò)得一個(gè)項(xiàng)目的),加深理解
假設(shè)我們?cè)谥鞔翱陬惖哪骋粋€(gè)槽函數(shù)allTransactionDone()中調(diào)用了QMessageBox::information()函數(shù),我們都知道,這會(huì)產(chǎn)生一個(gè)模態(tài)的對(duì)話框,對(duì)話框彈出后,我們不能操作主窗口,并且,此槽函數(shù)將阻塞到我們做出操作,按照上述邏輯,我們的第一反應(yīng)是,在槽函數(shù)返回前程序都無(wú)法維護(hù)事件循環(huán)隊(duì)列,主窗口發(fā)生的事件將得不到響應(yīng),例如主窗口有一個(gè)定時(shí)器一直觸發(fā)其相應(yīng)的槽函數(shù)去更新主窗口的圖像,那么,我們肯定認(rèn)為,此時(shí)主窗口的圖像將停止更新,其實(shí)不然,如果按照這種思維,那么當(dāng)我們?nèi)ゲ僮鲝棾龅腗essageBox時(shí)所產(chǎn)生的事件也將無(wú)法得到響應(yīng),那么程序?qū)o(wú)法進(jìn)行下去,真實(shí)的情況是QMessageBox::information()函數(shù)最終調(diào)用了QMessageBox::exec()來(lái)維護(hù)事件循環(huán)隊(duì)列,否則,按照上述邏輯,我們同樣不能操作彈出的模態(tài)對(duì)話框,QMessageBox::exec()程序維護(hù)的事件循環(huán)隊(duì)列和QApplication::exec()維護(hù)的是同一個(gè)事件循環(huán)隊(duì)列,并且Qt程序僅此一個(gè)事件循環(huán)隊(duì)列,這就像是Qt程序在處理某個(gè)事件時(shí),調(diào)用了processEvent()函數(shù)來(lái)將主線程的控制權(quán)交出去,去處理其他事件,處理完成后在收回控制權(quán)繼續(xù)處理當(dāng)前事件,當(dāng)前事件處理完成后最終將控制權(quán)返回給主循環(huán)。
allTransactionDone槽函數(shù):
void MainWindow::allTransactionDone(QString string)
{
? ? stack2OpenUi->beginPushButton->setEnabled(true);
? ? QImage image("C:/Users/yuechip/Desktop/asf/output/7.jpg");
? ? ui->resultLabel->setPixmap(QPixmap::fromImage(image).scaled(this->size, Qt::KeepAspectRatio));
? ? ui->resultStringLabel->setText(string);
? ? if(!this->saveResult)
? ? {
? ? ? ? QFile::remove(this->tempSaveResultFileName);
? ? }
? ? QFile::remove(this->tempJpgFileName);
? ? //只看這里
? ? QMessageBox::information(this, "information", "information");
}
最終程序運(yùn)行結(jié)果:
?
可以看出,當(dāng)MessageBox彈出時(shí),主窗口的更新并沒(méi)有停止,這也印證了上述表述。
?
總結(jié)
以上是生活随笔為你收集整理的QT-qevent 事件的accept()和ignore()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: nginx 的请求处理、请求的处理流程
- 下一篇: QT-概念笔记