事件概述
信号就是事件的一种,事件由用户触发;
鼠标点击窗口,也可以检测到事件;产生事件后,传给事件处理,判断事件类型,后执行事件相应函数;
类似单片机的中断(中断向量);
事件实验
工程准备
创建Qwidget基类工程且带UI
ui添加一个标签,这个标签拉得足够大,因为要显示
添加一个类文件Qwidget基类型的
更换为QLabel的基类
添加虚拟函数,属于保护类型;
输入void mousePressEvent(QMouseEvent *ev);如果参数不显示,删除括号且之后的删除;然后重新打括号
mylable.h
#ifndef MYLABLE_H
#define MYLABLE_H
#include <QWidget>
#include<QLabel>
#include<QMouseEvent>
class MyLable : public QLabel
{
Q_OBJECT
public:
explicit MyLable(QWidget *parent = 0);
protected:
void mousePressEvent(QMouseEvent *ev);
void mouseReleaseEvent(QMouseEvent *ev);
void mouseMoveEvent(QMouseEvent *ev);
signals:
public slots:
};
#endif // MYLABLE_H
mylable.c
#include "mylable.h"
#include<QString>
#include<QDebug>
MyLable::MyLable(QWidget *parent) : QLabel(parent)
{
this->setMouseTracking(true);//默认追踪鼠标,一开始不用点击窗口,就在追踪了
}
void MyLable::mousePressEvent(QMouseEvent *ev)
{
int i=ev->x();
int j=ev->y();
if(ev->button()==Qt::LeftButton)//左键
{
qDebug()<<"LeftButton";
}
else if(ev->button()==Qt::RightButton)//右键
{
qDebug()<<"RightButton";
}
else if(ev->button()==Qt::MidButton)//中间按键
{
qDebug()<<"MidButton";
}
//居中加粗指令
QString str=QString("<center><h1>press mouse:(%1 ,%2)</h1></center>").arg(i).arg(j);
this->setText(str);//设置标签内容为str
qDebug()<<str;
}
void MyLable::mouseReleaseEvent(QMouseEvent *ev)
{
}
void MyLable::mouseMoveEvent(QMouseEvent *ev)
{
}
<center> </center> //居中指令 后面加的 /属于闭合标记,相当于括号的最后一半括号
<h1> </h1> //加粗指令 后面加的 /属于闭合标记,相当于括号的最后一半括号
%1 %2 属于参数 1 和参数2; .arg(i) .arg(j) //添加对应变量
类提升
之前的标签基类,就变成了代码标签基类;
这个标签就成为了代码写的那个标标签;就可以显示文字了;
没有这个提升,就意味标签类不同,代码和UI的标签不是一个标签;
按键事件+定时器事件
开始一个定时器,分辨率为1ms 返回一个定时器ID
//停止定时器,只能使用kill
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include "mylable.h"
#include<QKeyEvent>//按键事件头
#include<QDebug>
#include<QTimerEvent>//定时器事件头
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
ID1_time =this->startTimer(1000);//开始一个定时器,分辨率为1ms 返回一个定时器ID
}
Widget::~Widget()
{
delete ui;
}
void Widget::keyPressEvent(QKeyEvent *e)//按键事件处理函数
{
qDebug()<< (char)e->key();//打印按键
if(e->key()==Qt::Key_A)//按键时这个就打印
{
qDebug()<< "Qt::Key_A";
}
}
void Widget::timerEvent(QTimerEvent *t)//定时器事件处理函数
{
if(t->timerId()==ID1_time)//判断当前的ID
{
static int time_counter;
qDebug()<< time_counter++;
if(time_counter==10)
{
this->killTimer(ID1_time);//停止定时器,只能使用kill
}
}
}
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include<QTimerEvent>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
protected://虚拟函数,都使用保护
void keyPressEvent(QKeyEvent *e);//虚拟函数,按键事件
void timerEvent(QTimerEvent *t);//虚拟函数,定时器事件
private:
Ui::Widget *ui;
int ID1_time;//定时器ID
};
#endif // WIDGET_H
按钮事件的接收和忽略
事件相当于信号量;使用就没有了;
新建一个类MyButton属于Qwidget基类;
把新建的构造函数和基类改成继承于QPushButton;
ui放一个按钮提升类
设计一个按键和处理信号,和一个事件
实验结果:connet按键的信号相当于一个按下事件,但是被鼠标事件占用了,所以按键的信号等不到了;
所以按键connet的事件是等待不到的,事件被使用具有消耗性;
如下是按键的鼠标按下事件
如下是按键按下信号和槽
按钮按下相当于事件。但是鼠标按下事件已经接受;所以传递不了给下方这个了;
所以下方无法被打印
事件传递只能传递给父类组件(父类窗口)
使用e->accept();//接收事件,事件不会向下传递
e->ignore();//忽略事件,事件会向下传递
代码设计为
按键的鼠标按下事件
void MyButton::mousePressEvent(QMouseEvent *e)
{
if(e->button()== Qt::LeftButton)
{
qDebug()<<"鼠标左按键被按下";
e->ignore();//忽略事件,传递给父组件,也就是主窗口;
//一般使用在关闭窗口,关闭窗口的时候,让事件传递;
//没有ignore,也就是信号已经被这个处理,信号相当于信号量,使用就没有了
}
else//否则左键没被按下 ,不做处理
{
QPushButton::mousePressEvent(e);//没被按下,就传递给父组件
}
}
父类的鼠标按下
void Widget::mousePressEvent(QMouseEvent *e)
{
qDebug()<<"+++++++++++++++++++";
}
void Widget::closeEvent(QCloseEvent *e)
{
int reg=QMessageBox::question(this,"question","是否需要关闭窗口");
if(reg==QMessageBox::Yes)
{
e->accept();//接收事件,事件不会向下传递
}
else
{
e->ignore();//忽略事件,事件会向下传递
}
}
event事件分发
事件分发分类分发给相应的事件处理函数;每个控件一个event。
在widget.h添加个
protected:
bool event(QEvent *e);//事件分发器 ,返回true就是说明事件已经被处理,停止向下传播
在widget.c分发器
bool Widget::event(QEvent *e)//
{
//事件按照类型分发
switch (e->type()) {
case QEvent::Close:
closeEvent(e);
break;
case QEvent::KeyPress:
keyPressEvent(e);
break;
default:
break;
} ;
if(e->type() == QEvent::Timer)
{
QTimerEvent *env= static_cast<QTimerEvent * >(e);
timerEvent( env);//处理定时事件 屏蔽这个,永远不会分发
return true;//返回true 表明事件被处理
}
else if(e->type() == QEvent::KeyPress)//事件是按键类型
{
QKeyEvent *env=static_cast<QKeyEvent*>(e) ;
if(env->key()==Qt::Key_B)
{
qDebug()<<"bbbbbBBBB";
}
}
else
{
return QWidget::event(e);//转发事件,继续下流事件
}
}
事件分发和过滤之间的关系:
过滤器
过滤器好处:不用单独给某个控件写事件分配EVENT;在过滤器里面可以,写一个EVENT程序,同时给多个器件使用;
成员的保护类添加如下
bool eventFilter(QObject *obj, QEvent *e);//过滤器 过滤的obj控件 e过滤的事件
返回ture 就是停止过滤,过滤完成 ,flase 未过滤完成;
过滤器代码
bool Widget::eventFilter(QObject *obj, QEvent *e)
{
if(obj== ui->pushButton)//这里可以并多个器件,相对写单个EVENT
{
if(e->type() == QEvent::MouseButtonPress)
{
qDebug()<<" 鼠标被按下 ";//处理
return true;//已经处理,不会继续传播
}
else
{
return QWidget::eventFilter(obj,e);//继续传播
}
}
else
{
return QWidget::eventFilter(obj,e);//则继续传递下去
}
}
补充知识点:
类型转换:
QTimerEvent *env= static_cast<QTimerEvent* >(e);
static_castt< >转换指令 ,符号里面是需要转换成的目标类型,(e)中的e是当前被转化数据;