Qt之ignore()和accept()
2014-03-15 21:06
369 查看
首先来看一段代码:
这是一段简单的代码,经过我们前面一段时间的学习,我们已经能够知道这段代码的运行结果:点击按钮,会在控制台打印出“You clicked this!”字符串。这是我们前面介绍过的内容。下面,我们向
我们重写了
clicked this!”字符串不再出现,只有一个“left”。也就是说,我们把父类的实现覆盖掉了。由此可以看出,父类
通过调用父类的同名函数,我们可以把 Qt 的事件传递看成链状:如果子类没有处理这个事件,就会继续向其父类传递。Qt 的事件对象有两个函数:
Qt,这个类的事件处理函数想要处理这个事件;后者则告诉 Qt,这个类的事件处理函数不想要处理这个事件。在事件处理函数中,可以使用
会从其父组件中寻找另外的接受者。
事实上,我们很少会使用
中的事件都是 protected 的,因此,重写的函数必定存在着其父类中的响应函数,所以,这个方法是可行的。为什么要这么做,而不是自己去手动调用这两个函数呢?因为我们无法确认父类中的这个处理函数有没有额外的操作。如果我们在子类中直接忽略事件,Qt 会去寻找其他的接收者,该子类的父类的操作会被忽略(因为没有调用父类的同名函数),这可能会有潜在的危险。为了避免自己去调用
做了特殊的设计:事件对象默认是 accept 的,而作为所有组件的父类
4000
这段代码在 Qt4 和 Qt5 中基本一致(区别在于
这段代码在一个
CustomButtonEx,结果是
这是因为我们重写了鼠标按下的事件,但是并没有调用父类函数或者显式设置
接下来我们继续测试,在
如果你把
会自动在标题上面的 [*] 位置替换成 * 号。我们使用 Lambda 表达式连接
true。然后我们需要重写
文章出处:http://www.devbean.net/2012/09/qt-study-road-2-events-accept-reject/
1234567891011121314151617181920212223242526272829303132333435 | //!!! Qt5// ---------- custombutton.h ---------- //class CustomButton : public QPushButton{ Q_OBJECTpublic: CustomButton(QWidget *parent = 0);private: void onButtonCliecked();}; // ---------- custombutton.cpp ---------- //CustomButton::CustomButton(QWidget *parent) : QPushButton(parent){ connect(this, &CustomButton::clicked, this, &CustomButton::onButtonCliecked);} void CustomButton::onButtonCliecked(){ qDebug() << "You clicked this!";} // ---------- main.cpp ---------- //int main(int argc, char *argv[]){ QApplication a(argc, argv); CustomButton btn; btn.setText("This is a Button!"); btn.show(); return a.exec();} |
CustomButton类添加一个事件函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // CustomButton ... protected: void mousePressEvent(QMouseEvent *event); ... // ---------- custombutton.cpp ---------- // ... void CustomButton::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { qDebug() << "left"; } else { QPushButton::mousePressEvent(event); } } ... |
CustomButton的
mousePressEvent()函数,也就是鼠标按下。在这个函数中,我们判断如果鼠标按下的是左键,则打印出来“left”字符串,否则,调用父类的同名函数。编译运行这段代码,当我们点击按钮时,“You
clicked this!”字符串不再出现,只有一个“left”。也就是说,我们把父类的实现覆盖掉了。由此可以看出,父类
QPushButton的
mousePressEvent()函数中肯定发出了
clicked()信号,否则的话,我们的槽函数怎么会不执行了呢?这暗示我们一个非常重要的细节:当重写事件回调函数时,时刻注意是否需要通过调用父类的同名函数来确保原有实现仍能进行!比如我们的
CustomButton了,如果像我们这么覆盖函数,
clicked()信号永远不会发生,你连接到这个信号的槽函数也就永远不会被执行。这个错误非常隐蔽,很可能会浪费你很多时间才能找到。因为这个错误不会有任何提示。这一定程度上说,我们的组件“忽略”了父类的事件,但这更多的是一种违心之举,一种错误。
通过调用父类的同名函数,我们可以把 Qt 的事件传递看成链状:如果子类没有处理这个事件,就会继续向其父类传递。Qt 的事件对象有两个函数:
accept()和
ignore()。正如它们的名字一样,前者用来告诉
Qt,这个类的事件处理函数想要处理这个事件;后者则告诉 Qt,这个类的事件处理函数不想要处理这个事件。在事件处理函数中,可以使用
isAccepted()来查询这个事件是不是已经被接收了。具体来说:如果一个事件处理函数调用了一个事件对象的
accept()函数,这个事件就不会被继续传播给其父组件;如果它调用了事件的
ignore()函数,Qt
会从其父组件中寻找另外的接受者。
事实上,我们很少会使用
accept()和
ignore()函数,而是像上面的示例一样,如果希望忽略事件(所谓忽略,是指自己不想要这个事件),只要调用父类的响应函数即可。记得我们曾经说过,Qt
中的事件都是 protected 的,因此,重写的函数必定存在着其父类中的响应函数,所以,这个方法是可行的。为什么要这么做,而不是自己去手动调用这两个函数呢?因为我们无法确认父类中的这个处理函数有没有额外的操作。如果我们在子类中直接忽略事件,Qt 会去寻找其他的接收者,该子类的父类的操作会被忽略(因为没有调用父类的同名函数),这可能会有潜在的危险。为了避免自己去调用
accept()和
ignore()函数,而是尽量调用父类实现,Qt
做了特殊的设计:事件对象默认是 accept 的,而作为所有组件的父类
QWidget的默认实现则是调用
ignore()。这么一来,如果你自己实现事件处理函数,不调用
QWidget的默认实现,你就等于是接受了事件;如果你要忽略事件,只需调用
QWidget的默认实现。这一点我们前面已经说明。下面可以从代码级别来理解这一点,我们可以查看一下
QWidget的
mousePressEvent()函数的实现:
4000
1234567891011121314151617 | //!!! Qt5void QWidget::mousePressEvent(QMouseEvent *event){ event->ignore(); if ((windowType() == Qt::Popup)) { event->accept(); QWidget* w; while ((w = QApplication::activePopupWidget()) && w != this){ w->close(); if (QApplication::activePopupWidget() == w) w->hide(); // hide at least } if (!rect().contains(event->pos())){ close(); } }} |
activePopupWidget()一行,Qt4 的版本是
qApp->activePopupWidget())。注意函数的第一个语句:
event->ignore(),如果子类都没有重写这个函数,Qt 会默认忽略这个事件,继续寻找下一个事件接收者。如果我们在子类的
mousePressEvent()函数中直接调用了
accept()或者
ignore(),而没有调用父类的同名函数,
QWidget::mousePressEvent()函数中关于
Popup判断的那段代码就不会被执行,因此可能会出现默认其妙的怪异现象。针对
accept()和
ignore(),我们再来看一个例子:C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | class CustomButton : public QPushButton { Q_OBJECT public: CustomButton::CustomButton(QWidget *parent) : QPushButton(parent) { } protected: void mousePressEvent(QMouseEvent *event) { qDebug() << "CustomButton"; } }; class CustomButtonEx : public CustomButton { Q_OBJECT public: CustomButtonEx::CustomButtonEx(QWidget *parent) : CustomButton(parent) { } protected: void mousePressEvent(QMouseEvent *event) { qDebug() << "CustomButtonEx"; } }; class CustomWidget : public QWidget { Q_OBJECT public: CustomWidget::CustomWidget(QWidget *parent) : QWidget(parent) { } protected: void mousePressEvent(QMouseEvent *event) { qDebug() << "CustomWidget"; } }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow::MainWindow(QWidget *parent = 0) : QMainWindow(parent) { CustomWidget *widget = new CustomWidget(this); CustomButton *cbex = new CustomButton(widget); cbex->setText(tr("CustomButton")); CustomButtonEx *cb = new CustomButtonEx(widget); cb->setText(tr("CustomButtonEx")); QVBoxLayout *widgetLayout = new QVBoxLayout(widget); widgetLayout->addWidget(cbex); widgetLayout->addWidget(cb); this->setCentralWidget(widget); } protected: void mousePressEvent(QMouseEvent *event) { qDebug() << "MainWindow"; } }; |
MainWindow中添加了一个
CustomWidget,里面有两个按钮对象:
CustomButton和
CustomButtonEx。每一个类都重写了
mousePressEvent()函数。运行程序点击
CustomButtonEx,结果是
1 | CustomButtonEx |
accept()或
ignore()。下面我们在
CustomButtonEx的
mousePressEvent()第一行增加一句
event->accept(),重新运行,发现结果不变。正如我们前面所说,
QEvent默认是
accept的,调用这个函数并没有什么区别。然后我们将
CustomButtonEx的
event->accept()改成
event->ignore()。这次运行结果是
1 2 | CustomButtonEx CustomWidget |
ignore()说明我们想让事件继续传播,于是
CustomButtonEx的父组件
CustomWidget也收到了这个事件,所以输出了自己的结果。同理,
CustomWidget又没有调用父类函数或者显式设置
accept()或
ignore(),所以事件传播就此打住。这里值得注意的是,
CustomButtonEx的事件传播给了父组件
CustomWidget,而不是它的父类
CustomButton。事件的传播是在组件层次上面的,而不是依靠类继承机制。
接下来我们继续测试,在
CustomWidget的
mousePressEvent()中增加
QWidget::mousePressEvent(event)。这次的输出是
123 | CustomButtonExCustomWidgetMainWindow |
QWidget::mousePressEvent(event)改成
event->ignore(),结果也是一样的。这正如我们前面说的,
QWidget的默认是调用
event->ignore()。不过,事情也不是绝对的。在一个情形下,我们必须使用
accept()和
ignore()函数,那就是窗口关闭的事件。注意,不要试图用前面了解到的有关
accept()和
ignore()的知识来理解这个事件!对于
QCloseEvent事件,调用
accept()意味着 Qt 会停止事件的传播,调用
ignore()则意味着事件继续传播。这与前面所说的正好相反。回到我们前面写的简单的文本编辑器。我们在构造函数中添加如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //!!! Qt5 ... textEdit = new QTextEdit(this); setCentralWidget(textEdit); connect(textEdit, &QTextEdit::textChanged, [=]() { this->setWindowModified(true); }); setWindowTitle("TextPad [*]"); ... void MainWindow::closeEvent(QCloseEvent *event) { if (isWindowModified()) { bool exit = QMessageBox::question(this, tr("Quit"), tr("Are you sure to quit this application?"), QMessageBox::Yes | QMessageBox::No, QMessageBox::No) == QMessageBox::Yes; if (exit) { event->accept(); } else { event->ignore(); } } else { event->accept(); } } |
setWindowTitle()函数可以使用 [*] 这种语法来表明,在窗口内容发生改变时(通过
setWindowModified(true)函数通知),Qt
会自动在标题上面的 [*] 位置替换成 * 号。我们使用 Lambda 表达式连接
QTextEdit::textChanged()信号,将
windowModified设置为
true。然后我们需要重写
closeEvent()函数。在这个函数中,我们首先判断是不是有过修改,如果有,则弹出询问框,问一下是否要退出。如果用户点击了“Yes”,则接受关闭事件,这个事件所在的操作就是关闭窗口。因此,一旦接受事件,窗口就会被关闭;否则窗口继续保留。当然,如果窗口内容没有被修改,则直接接受事件,关闭窗口。
文章出处:http://www.devbean.net/2012/09/qt-study-road-2-events-accept-reject/
相关文章推荐
- qt中 accept()和ignore()函数
- QT的父子Widget之间消息的传递(如果子类没有accept或ignore该事件,则该事件会被传递给其父亲——Qlabel与QPushButton的处理就不一样)
- qt ignore()和accept()函数
- Qt的QEvent::accept()和QEvent::ignore()
- <Qt>事件的accept()与ignore()的传递
- QT——绘图事件、鼠标事件、QPainter、键盘事件、光标样式、登录框密码回显模式、移除字符串前后的空白、对话框accept()
- QT总结第6篇:模式对话框和非模式对话框(exec()/accept())
- qevent accept()和ignore() 函数
- QEvent ignore accept()
- 2015.6.5 qt学习笔记 accept()概念
- 事件的接受与忽略 accept() ignore() protected成员
- Qt 的几个核心机制总结之 布局(QWidget可以设置setSizePolicy,而QSizePolicy有Fixed,minimum,maximum,preferred,expanding,ignore等7个属性,还可以横竖分开)
- Qt中QEvent的accept和ignore函数 事件 (以QLabel事件重载为例)
- qt: exec()的用法,accept()和accepted的概念
- qt: exec()的用法,accept()和accepted的概念
- (13)accept()和ignore()--事件的处理
- qevent 事件的accept()和ignore()
- 基于Qt 4.6的Qt Creator 1.3.0环境变量设置
- Qt QTableWidget
- 嵌入式成长轨迹34 【嵌入式学习阶段】【ARM环境调试】【QT 移植环境及简单程序示例】---补充《ok6410 Qt移植百科全书》