事件
事件文章目录事件一、 事件二、event一、 事件1 . 事件(event) 是由系统或者 Qt 本身在不同的时刻发出的。 当用户按下鼠标、 敲下键盘, 或者是窗口需要重新绘制的时候, 都会发出一个相应的事件。 一些事件在对用户操作做出响应时发出, 如键盘事件等; 另一些事件则是由系统自动发出,如计时器事件。在前面我们也曾经简单提到, Qt 程序需要在 main()函数创建一个QApp...
事件
一、 事件
1 . 事件(event) 是由系统或者 Qt 本身在不同的时刻发出的。 当用户按下鼠标、 敲下键盘, 或者是窗口需要重新绘制的时候, 都会发出一个相应的事件。 一些事件在对用户操作做出响应时发出, 如键盘事件等; 另一些事件则是由系统自动发出,如计时器事件。
- 在前面我们也曾经简单提到, Qt 程序需要在 main()函数创建一个QApplication 对 象, 然后调用它的exec()函数。
- 这个函数就是
开始 Qt 的事件循环。 - 在执行 exec() 函数之后,程序将进入事件循环来监听应用程序的事件。
- 当
事件发生时, Qt 将 创建一个事件对象。 -
Qt 中所有事件类都继承于 QEvent - 在
事件对象创建完毕后, Qt 将这个事件对象传递给 QObject 的 event()函数。 - event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler)
在所有组件的父类 QWidget 中, 定义了很多事件处理的回调函数, 如:
keyPressEvent()
keyReleaseEvent()
mouseDoubleClickEvent()
mouseMoveEvent()
mousePressEvent()
mouseReleaseEvent() 等
这些函数都是 protected virtual 的, 也就是说, 我们可以在子类中重新实现这些函数。
2. mousePressEvent函数:
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
作用:这个事件处理程序(用于事件事件)可以在子类中重新实现,以接收小部件的鼠标按下事件。如果您在mousePressEvent()中创建新的小部件,那么mouseReleaseEvent()可能不会在您期望的地方结束,这取决于底层小部件类型,它什么也不做。
3. mouseReleaseEvent函数:
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
作用:这个事件处理程序(用于事件事件)可以在子类中重新实现,以接收小部件的鼠标释放事件
4. mouseMoveEvent函数
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
作用:这个事件处理程序(用于事件事件)可以在子类中重新实现,以接收小部件的鼠标移动事件如果关闭鼠标跟踪,鼠标移动事件仅在鼠标移动时按下鼠标按钮时发生。如果打开鼠标跟踪,即使没有按下鼠标按钮,也会发生鼠标移动事件
5.Qt的sprintf
QString 的 arg()函数可以自动替换掉 QString 中出现的占位符。 其占位符以 %
开始, 后面是占位符的位置,
例如 %1, %2 这种。
QString("[%1, %2]").arg(x).arg(y);
语句将会使用 x 替换 %1, y 替换 %2, 因此, 生成的 QString 为[x, y]。
QString str = QString("i am %1;i age %2").arg("wolf").arg(22);
qDebug()<<str;
6.enterEvent函数:
[virtual protected] void QWidget::enterEvent(QEvent *event)
作用:可以在子类中重新实现此事件处理程序来接收小部件输入事件,这些事件在事件参数中传递。当鼠标光标进入小部件时,一个事件被发送到小部件。
7.leaveEvent函数:
[virtual protected] void QWidget::leaveEvent(QEvent *event)
作用:可以在子类中重新实现此事件处理程序,以接收在事件参数中传递的小部件休假事件。当鼠标离开小部件时,将向小部件发送leave事件。
8.QMouseEvent
头文件
#icnlude <QMouseEvent>
9.keyPressEvent函数
[virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
作用:这个事件处理程序(用于事件事件)可以在子类中重新实现,以接收小部件的按键事件
10.keyReleaseEvent函数:
[virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event)
作用:这个事件处理程序(用于事件事件)可以在子类中重新实现,以接收小部件的键释放事件。
11.完整代码:
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void keyPressEvent(QKeyEvent *event);
void keyReleaseEvent(QKeyEvent *event);
void timerEvent(QTimerEvent *event);
int id;
int timeid;
#include "mylabel.h"
#include <QMouseEvent>
#include <QDebug>
MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
//设置追踪鼠标,一进对话框就有效
setMouseTracking(true);
}
//鼠标点击事件
void MyLabel::mousePressEvent(QMouseEvent *ev)
{
//获取xy坐标
int i = ev->x();
int j = ev->y();
//判断点击的类型
if(ev->button() == Qt::LeftButton)
{
qDebug()<<"i am left";
}
else if(ev->button() == Qt::RightButton)
{
qDebug()<<"i am right";
}
else if(ev->button() == Qt::MidButton)
{
qDebug()<<"i am mid";
}
//在对话框上显示内容
QString text = QString("<center><h1>Mouse Press : (%1,%2)</h1></center>").arg(i).arg(j);
this ->setText(text);
}
//鼠标抬起事件
void MyLabel::mouseReleaseEvent(QMouseEvent *ev)
{
//设定内容
QString text = QString("<center><h1>Mouse Release : (%1,%2)</h1></center>").arg(ev->x()).arg(ev->y());
this ->setText(text);
}
//鼠标移动事件
void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
QString text = QString("<center><h1>Mouse Move : (%1,%2)</h1></center>").arg(ev->x()).arg(ev->y());
this ->setText(text);
}
//鼠标进入控件事件
void MyLabel::enterEvent(QEvent *event)
{
QString text = QString("<center><h1>Mouse enter window</h1></center>");
this ->setText(text);
}
//鼠标离开控件事件
void MyLabel::leaveEvent(QEvent *event)
{
QString text = QString("<center><h1>Mouse leave window</h1></center>");
this ->setText(text);
}
//鼠标按下按键事件
void MyWidget::keyPressEvent(QKeyEvent *event)
{
//qDebug()<<(char)event->key();
//判断用户按下的是什么按键
if(event->key() == Qt::Key_A)
{
qDebug()<<"i am A";
}
else if(event->key() == Qt::Key_Shift)
{
qDebug()<<"i am shift";
}
else if(event->key() == Qt::Key_0)
{
qDebug()<<"i am key_0";
}
}
//鼠标抬起按键事件
void MyWidget::keyReleaseEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_A)
{
qDebug()<<"i am A";
}
else if(event->key() == Qt::Key_Shift)
{
qDebug()<<"i am shift";
}
else if(event->key() == Qt::Key_0)
{
qDebug()<<"i am key_0";
}
}
//设定定时器事件
void MyWidget::timerEvent(QTimerEvent *event)
{
//对不同的定时器进行区分
if(event->timerId() == id)
{
static int i = 0;
i++;
ui->label->setText(QString("<center><h1>timeout : [%1]</h1></center>").arg(i));
if(i == 6)
{
killTimer(id);
}
}
else if (event->timerId() == timeid)
{
static int i = 0;
i++;
ui->label_2->setText(QString("<center><h1>timeout : [%1]</h1></center>").arg(i));
if(i == 6)
{
killTimer(timeid);
}
}
}
//事件的传递和忽略
void MyWidget::closeEvent(QCloseEvent *event)
{
//建造一个问题对话框
int ret = QMessageBox::question(this,"close","are you sure");
//如果按下的是YES就关闭窗口
if(ret == QMessageBox::Yes)
{
qDebug()<<"i am closed window";
//事件不会往下传
event->accept();
}
else if(ret == QMessageBox::No)
{
qDebug()<<"i am no close window";
//不会关闭窗口,事件会传递给父组件
event->ignore();
}
}
二、event
1.event函数
[virtual protected] bool QWidget::event(QEvent *event)
事件对象创建完毕后, Qt 将这个事件对象传递给 QObject 的 event()函数。 event()函数并不直接处理事件, 而是将这些事件对象按照它们不同的类型, 分发给不同的事件处理器(event handler)。
event()函数主要用于事件的分发。 所以, 如果你希望在事件分发之前
做一些操作, 就可以重写这个 event()函数了。 例如, 我们希望在一个 QWidget
组件中监听 tab 键的按下, 那么就可以继承 QWidget, 并重写它的 event()函数,
来达到这个目的:
bool CustomWidget::event(QEvent *e)
{
if (e->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if (keyEvent->key() == Qt::Key_Tab)
{
qDebug() << "You press tab.";
return true;
}
}
return QWidget::event(e);
}
CustomWidget 是一个普通的 QWidget 子类。 我们重写了它的 event()函数, 这个函数有一个 QEvent 对象作为参数, 也就是需要转发的事件对象。 函数返回值是 bool类型
-
如果传入的事件已被识别并且处理, 则需要返回 true, 否则返回 false。 如果 返回值是 true, 那么 Qt会认为这个事件已经处理完毕, 不会再将这个事件 发送给其它对象, 而是会继续处理事件队列中的下一事件。 -
在 event()函数中, 调用事件对象的 accept()和 ignore()函数是没有作用的, 不会影响到事件的传播。
2. 我们可以通过使用 QEvent::type()函数可以检查事件的实际类型
其返回值是QEvent::Type 类型的枚举。 我们处理过自己感兴趣的事件之后, 可以直接返回 true,表示我们已经对此事件进行了处理; 对于其它我们不关心的事件, 则需要调用父类的 event()函数继续转发, 否则这个组件就只能处理我们定义的事件了。 为了测试这一种情况, 我们可以尝试下面的代码:
bool CustomTextEdit::event(QEvent *e)
{
if (e->type() == QEvent::KeyPress)
{
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
if (keyEvent->key() == Qt::Key_Tab)
{
qDebug() << "You press tab.";
return true;
}
}
return false;
}
CustomTextEdit 是 QTextEdit 的一个子类。 我们重写了其 event()函数, 却没有调用父类的同名函数。 这样, 我们的组件就只能处理 Tab 键, 再也无法输入任何文
本, 也不能响应其它事件, 比如鼠标点击之后也不会有光标出现。 这是因为我们
只处理的 KeyPress 类型的事件, 并且如果不是 KeyPress 事件, 则直接返回 false, 鼠标事件根本不会被转发, 也就没有了鼠标事件。
3. 通过查看 QObject::event()的实现, 我们可以理解, event()函数同前面的事件处理器有什么联系
//!!! Qt5
bool QObject::event(QEvent *e)
{
switch (e->type()) {
case QEvent::Timer:
timerEvent((QTimerEvent*)e);
break;
case QEvent::ChildAdded:
case QEvent::ChildPolished:
case QEvent::ChildRemoved:
childEvent((QChildEvent*)e);
break;
// ...
default:
if (e->type() >= QEvent::User) {
customEvent(e);
break;
}
return false;
}
return true;
}
这是 Qt 5 中 QObject::event()函数的源代码(Qt 4 的版本也是类似的) 。 我们可以看到, 同前面我们所说的一样, Qt 也是使用 QEvent::type()判断事件类型, 然后调用了特定的事件处理器。 比如, 如果 event->type()返回值是 QEvent::Timer, 则调用 timerEvent()函数。 可以想象, QWidget::event()中一定会有如下的代码
switch (event->type()) {
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break;
// ...
}
事实也的确如此。 timerEvent()和 mouseMoveEvent()这样的函数, 就是我们所说的事件处理器 event handler。 也就是说, event()函数中实际是通过事件处
理器来响应一个具体的事件。 这相当于 event()函数将具体事件的处理“委托”给具
体的事件处理器。 而这些事件处理器是 protected virtual 的, 因此, 我们重写了
某一个事件处理器, 即可让 Qt 调用我们自己实现的版本。
由此可以见, event()是一个集中处理不同类型的事件的地方。 如果你不想重写一大堆事件处理器, 就可以重写这个 event()函数, 通过 QEvent::type()判断不同的事件。 鉴于重写 event()函数需要十分小心注意父类的同名函数的调用, 一不留神就可能出现问题, 所以一般还是建议只重写事件处理器(当然, 也必须记得是不是应该调用父类的同名处理器) 。 这其实暗示了 event()函数的另外一个作用: 屏蔽掉某些不需要的事件处理器。 正如我们前面的 CustomTextEdit 例子看到的那样,我们创建了一个只能响应 tab 键的组件。 这种作用是重写事件处理器所不能实现的
更多推荐


所有评论(0)