事件Event

事件是由窗口系统和Qt自身产生的,用以响应发生的各类事情,例如用户按下键盘或者鼠标,都会产生一个键盘或鼠标的事件。大多数事件是用于的动作相应的,小数是由系统独立产生的,如定时器事件。要记住“事件”和“信号”是两种不同的概念。

 

重载键盘事件函数:

如果我们想自定义事件处理函数,只需要重载相关的事件函数就行了,如我需要对点击F3”按键的事件进行处理,代码如下:

//重载keyPressEvent()

void MainWindow::keyPressEvent(QKeyEvent *event)

{    

if(event->key() == Qt::Key_F3)    

{        

//todu    

}

//把事件传递给父窗口部件来处理

QWidget::keyPressEvent(event);

}

 

定时器事件:

调用startTimer()后会分配一个唯一的标识号,每隔一段时间都会调用一次timerEvent()

//mainwindow.h

void timerEvent(QTimerEvent *event);

int myTimerId;

 

//mainwindow.cpp

//开启定时器

myTimerId = startTimer(500);

 

void MainWindow::timerEvent(QTimerEvent *event)

{    

if(myTimerId == event->timerId())    

{        

//todo    

}

}

//关闭定时器

killTimer(myTimerId);        

myTimerId = 0;

 

补充:

定时器还可以这样用QTimer::singleShot(0, this, SLOT(function()));功能是马上触发定时器执行槽函数,这种用法多用于构造函数中耗时较长的初始功能,为了避免因为耗时的原因界面没有加载出来,使用户认为是应用程序启动失败。

定时器事件是一种低级事件,当需要多个定时器时,一个定时器对应一个ID这会让追踪定时器变得困难,因此最好的方法是创建QTimer对象。

 

事件过滤器:

假设现在有一个需求,界面上有四个QLineEdit,点击QlineEdit后光标在上面显示,当我们输入空格键时光标调到下一个QLineEdit上。

我们可以子类化QLineEdit,用上面重载键盘事件函数的方法实现,但当是不同的窗口部件(QSpinBox,QComboBox等)之间实现这个需求时,子类化每个窗口部件类是非常麻烦的,所以我们可以用事件过滤器实现。

Qt事件模型的一个非常强大的功能是QObject实例(例如窗口部件)在看到它自己的事件之前,可以通过设置另一个QObject实例先监视这些事件。我的理解是父窗体可以先监视子窗口的事件,并在监视代码中实现相应功能。

使用过滤器的步骤为:

1、目标对象(窗口部件)调用installEventFilter()注册监视对象

2、在监视对象的eventFilter()中处理目标对象(窗口部件)的事件。

过滤器代码实例:

//mainwindow.h

QLineEdit *lineEdit1;    

QLineEdit *lineEdit2;

void eventFilter(QObject *target, QEvent *event);

 

//mainwindow.cpp

//构造函数中

{

...

lineEdit1 = new QLineEdit(this);    

lineEdit2 = new QLineEdit(this);    

lineEdit1->installEventFilter(this);    

lineEdit2->installEventFilter(this);

...

}

//重载eventFilter()

bool MainWindow::eventFilter(QObject *target, QEvent *event)

{    

//检查目标对象

if(target == lineEdit1 || target == lineEdit2)    

{        

//判断是否键盘按下事件

if(event->type() == QEvent::KeyPress)        

{   

//将事件强制转换为键盘事件,为了可以调用keyEvent->key()         

QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);             //判断是否空格键

if(keyEvent->key() == Qt::Key_Space)

{                

//todo                

return true;           

 }       

}

    }

//如果目标对象不对,不是按键按下事件,就调用基类的eventFilter,因为基类eventFilter也可能正在监控某个窗口部件。

    return QWidget::eventFilter(target,event);

}

 

Qt提供五个级别的事件处理和时间过滤方法(序号越大级别越高):

1、重新实现特殊的事件处理器

即重载按键按下,鼠标单击等事件处理函数

2、重新实现QObject:event()

通过event()函数的重新实现,可以让事件到达特定的事件处理器前处理它们。

3、Object中安装事件过滤器

4、QApplicantion对象中安装事件过滤器

应用程序的每个对象都会在事件发送到其他事件过滤器之前,先发送给这个eventFilter()函数。

5、子类化QApplicantion并且重载notify()

 

QApplicatn::processEvent():

当调用QApplicant:exec()时,就启动了Qt的事件循环。当处理一个事件时(执行功能函数),也有可能有产生别的事件并会添加到事件队列中。当处理这个事件耗时太长时,其他事件无法进行,用户界面就无法响应了,如无法进行鼠标点击,这时解决的方法有两种:

1、利用多线程方法,将处理应用程序的用户界面和耗时的操作分开为不同的线程

2、频繁调用QApplicatn::processEvent(),这个函数的作用是告诉Qt处理那些还没被处理的事件,这可以让用户界面继续操作,因此QApplicant:exec()就是一个不断调用QApplicatn::processEvent()while循环。

 posted on 2020-12-06 15:16  拳击手乌小冬  阅读(92)  评论(0编辑  收藏  举报