事件是应用程序内部或者外部产生的事情或者动作的统称
例如:
- 鼠标事件
- 键盘事件
- 定时器事件
就好比是信号那样子
事件处理
事件处理⼀般常用的方法为:重写相关的 Event 函数
在qt中几乎所有的 Event 函数都是虚函数,所以可以重新实现业务处理。
鼠标事件
进入离开事件
实现一个鼠标进入到 label 控件和离开 label 控件时分别修改 label 的文本
首先需要新建一个 QLabel 的子类并重写这两个事件
注意,在进行下面的操作前,需要先把控件给提升为自己新建的类,否则操作自己新建的类是不会对控件产生效果的。因为没有提升之前的空间是属于 QWidget的
接着在 mylabel.cpp 中重写这两个事件虚函数
void MyLabel::enterEvent(QEvent *event)
{
(void)event;
this->setText("鼠标进来了");
}
void MyLabel::leaveEvent(QEvent *event)
{
(void)event;
this->setText("鼠标离开了");
}
单击事件
这个点击事件包含了鼠标上的 左键、右键、滚轮以及侧键这些标准按键的点击事件。
注意这个 mousePressEvent 函数的参数,这个参数里包含了鼠标点击的坐标,其中坐标又可以分为两种
- 直接调用 x y:这是相对于点击的控件的坐标
- 调用 globalx globaly:这是相当于屏幕的坐标
因此基于以上性质,实现一个鼠标左键点击则打印相对控件坐标,鼠标右键点击则打印相对屏幕坐标,滚轮则打印 滚轮 两个字
void MyLabel::mousePressEvent(QMouseEvent *event)
{
// 鼠标左键
if(event->button() == Qt::LeftButton)
{
this->setText("左键:" +
QString::number(event->x()) +
", " +
QString::number(event->y()));
}
// 鼠标右键
if(event->button() == Qt::RightButton)
{
this->setText("右键:" +
QString::number(event->globalX()) +
", " +
QString::number(event->globalY()));
}
// 鼠标滚轮
if(event->button() == Qt::MidButton){
this->setText("滚轮");
}
}
释放事件
不同于单击事件,这个需要点了之后必须释放才会触发,而单击事件只要点了不释放也会释放。
void MyLabel::mouseReleaseEvent(QMouseEvent *event)
{
// 鼠标左键
if(event->button() == Qt::LeftButton)
{
this->setText("左键释放");
}
// 鼠标右键
if(event->button() == Qt::RightButton)
{
this->setText("右键释放");
}
// 鼠标滚轮
if(event->button() == Qt::MidButton){
this->setText("滚轮释放");
}
}
双击事件
需要鼠标双击才可以触发
void MyLabel::mouseDoubleClickEvent(QMouseEvent *event)
{
// 鼠标左键
if(event->button() == Qt::LeftButton)
{
this->setText("左键双击");
}
// 鼠标右键
if(event->button() == Qt::RightButton)
{
this->setText("右键双击");
}
// 鼠标滚轮
if(event->button() == Qt::MidButton){
this->setText("滚轮双击");
}
}
移动事件
鼠标移动时触发
这个需要搭配 setMouseTracking 函数使用,由于鼠标的追踪状态默认是关闭的,所以需要 setMouseTracking 设为true,否则鼠标只有在点击的时候才会触发。
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置鼠标追踪状态
setMouseTracking(true);
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
ui->label->setText("鼠标位置:" +
QString::number(event->x()) +
";" +
QString::number(event->y()));
}
滚轮事件
滚轮事件的参数为 QWheelEvent 类型,这个类里面有一个函数 delta 用来获取滚轮滑动的距离。
void Widget::wheelEvent(QWheelEvent *event)
{
static int x = 0;
x += event->delta();
ui->label->setText("滚轮滑动距离:" +
QString::number(x));
}
按键事件
按键事件是通过 QKeyEvent 类来实现的
单个按键按下
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_A)
ui->label->setText("A按键被按下");
if(event->key() == Qt::Key_B)
ui->label->setText("B按键被按下");
}
组合按键
代码 | 说明 |
---|---|
Qt::NoModifier | 无修改 |
Qt::ShiftModifier | Shift |
Qt::ControlModifier | Ctrl |
Qt::AltModifier | Alt |
Qt::MetaModifier | Meta(Win/Command) |
Qt::KeypadModifier | 数字键盘 |
Qt::GroupSwitchModifier | 输入法之间切换 |
这些都是定义了在处理键盘事件时对应的修改键,这些修改键可以和键盘事件组合使用。
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->modifiers() == Qt::ControlModifier)
{
if(event->key() == Qt::Key_A)
ui->label->setText("Ctrl + A按键被按下");
if(event->key() == Qt::Key_B)
ui->label->setText("Ctrl + B按键被按下");
}
}
定时器事件
Qt中的定时器分为 QTimerEvent 和 QTimer
- QTimerEvent 用来描述一个定时器事件。需要通过 startTimer 函数开启一个定时器,以毫秒为单位,返回值代表这个定时器。当事件到了就可以在 timerEvent 函数中获取该定时器的编号来进行业务处理
- QTimer 用来实现一个定时器,相比前者有更高层次的接口,可以使用信号和槽,也可以设置只运行一次
QTimerEvent
首先添加定时器和需要显示的变量为类的私有成员变量,重写时才可以调用得到
重写事件
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 启动定时器
timer1 = startTimer(1000);
timer2 = startTimer(2000);
}
void Widget::timerEvent(QTimerEvent *e)
{
// timer1定时器管理label_1
if(e->timerId() == timer1)
ui->label->setText(QString::number(num1++));
// timer2定时器管理label_2
if(e->timerId() == timer2)
ui->label_2->setText(QString::number(num2++));
}
QTimer
设计一个倒计时器,使用 QLCDNumber 控件来显示
QLCDNumber *num = new QLCDNumber(this);
num->display(5); num->setGeometry(100, 100, 100, 100);
num->setSegmentStyle(QLCDNumber::Flat);
// 创建QTimer定时器成员
QTimer *time = new QTimer(this);
// 每个一秒显示器的数字减1,数字为0时关闭定时器
connect(time, &QTimer::timeout, this, [=](){
int n = num->intValue();
if(n <= 0)
{
time->stop();
Widget::close(); // 关闭窗口
}
num->display(n - 1);
});
// 设置定时器每隔一秒触发一次
time->start(1000);
获取系统日期及时间
获取系统的日期及实时时间可以通过 QTimer 类 和 QDateTime类
QDateTime 类提供了字符串格式的时间。字符串形式的时间输出格式由 toString() 方法中的 format 参数列表决定。
实现显示实时时间
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QTimer *timer = new QTimer(this);
// 每隔一秒更新一次实时时间
connect(timer, &QTimer::timeout, this, [=](){
// 获取实时时间并格式化
QString s = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
// 显示到 label
ui->label->setText(s);
});
// 启动定时器
timer->start(1000);
}
事件分发器
事件分发器负责将事件从⼀个对象传递到另⼀个对象,直到事件被处理或被取消。
每个继承自 QObject 类或 QObject 类本⾝都可以在本类中重写 bool event(QEvent *e) 函数,来实现相关事件的捕获和拦截。
event 函数如果返回 true 就不会再向下分发了。
// 事件分发器处理
bool Widget::event(QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
ui->label->setText("事件分发器");
return true; // 返回 true 就不会再将事件分给其他的event函数了
}
// 其他事件交给父类处理
return QWidget::event(event);
}
// 鼠标释放事件处理
void Widget::mousePressEvent(QMouseEvent *event)
{
(void)event;
ui->label->setText("mouseReleaseEvent");
}
可以看到这样子鼠标单击事件就被事件分发器处理了,轮不到 mousePressEvent 去处理了。
事件过滤器
⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到或者修改按键的默认值等。
事件过滤器是在应用程序分发到 event事件分发器之前,再做一次更高级的拦截
使用步骤:
- 安装事件过滤器
- 重写事件过滤器函数:eventfilter
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 给控件安装一个过滤器
ui->label->installEventFilter(this);
}
// 事件过滤器处理
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
if(obj == ui->label)
{
if(event->type() == QEvent::MouseButtonPress)
{
ui->label->setText("事件过滤器");
return true; // 返回 true 就不会再将事件分给其他的event函数了
}
}
// 其他事件交给父类处理
return QWidget::eventFilter(obj, event);
}
// 事件分发器处理
bool Widget::event(QEvent *event)
{
if(event->type() == QEvent::MouseButtonPress)
{
ui->label->setText("事件分发器");
return true; // 返回 true 就不会再将事件分给其他的event函数了
}
// 其他事件交给父类处理
return QWidget::event(event);
}
// 鼠标释放事件处理
void Widget::mousePressEvent(QMouseEvent *event)
{
(void)event;
ui->label->setText("mouseReleaseEvent");
}
可以看到当点击安装了过滤器的控件时就不会执行到事件分发器了