【QT】Qt事件

目录

前置知识

事件概念

常见的事件描述

进入和离开事件

代码示例: 

鼠标事件

鼠标点击事件

鼠标释放事件 

鼠标双击事件

鼠标滚轮动作

键盘事件

定时器事件

开启定时器事件

窗口相关事件

窗口移动触发事件 

窗口大小改变时触发的事件

扩展


前置知识

        在前面的介绍中,我们知道信号槽就是:用户进行的各种操作,就可能会产生出信号,可以给某个信号指定槽函数,当信号触发时,就能够自动的执行对应的槽函数。

        这里的事件也是类似的,用户进行的各种操作,也会产生事件,程序员同样可以给事件关联上处理函数(处理的逻辑),当事件触发的时候,就能够执行到对应的代码。

        事件本身是操作系统提供的机制,Qt也同样把操作系统的事件机制进行了封装,拿到了Qt中,但是由于事件对应的代码编写起来不是很方便,Qt对于事件机制又进行了进一步的封装,就得到了信号槽。

        也就是说,信号槽就是对于事件的进一步封装,事件是信号槽的底层机制

        实际上Qt开发过程中,绝大部分和用户之间进行的交互都是通过“信号槽”,来完成的,有些特殊情况下,信号槽不一定能搞定(某个用户的动作行为,Qt中没有提供对应的信号……)此时就需要通过重写事件处理函数的形式,来手动处理事件的响应逻辑。

事件概念

        事件是应⽤程序内部或者外部产⽣的事情或者动作的统称。在 Qt 中使⽤⼀个对象来表⽰⼀个事件。所有的 Qt 事件均继承于抽象类 QEvent。事件是由系统或者 Qt 平台本⾝在不同的时刻发出的。当⽤⼾按下⿏标、敲下键盘,或者是窗⼝需要重新绘制的时候,都会发出⼀个相应的事件。⼀些事件是在⽤⼾操作时发出,如键盘事件、⿏标事件等,另⼀些事件则是由系统本⾝⾃动发出,如定时器事件。常⻅的 Qt 事件如下:

常见的事件描述

事件名称描述
⿏标事件
⿏标左键、⿏标右键、⿏标滚轮,⿏标的移动,⿏标按键的按下和松开
键盘事件
按键类型、按键按下、按键松开
定时器事件
定时时间到达
进⼊离开事件
⿏标的进⼊和离开
滚轮事件
⿏标滚轮滚动
绘屏事件
重绘屏幕的某些部分
显⽰隐藏事件
窗⼝的显⽰和隐藏
移动事件
窗⼝位置的变化
窗⼝事件
是否为当前窗⼝
⼤⼩改变事件
窗⼝⼤⼩改变
焦点事件
键盘焦点移动
拖拽事件
⽤⿏标进⾏拖拽

进入和离开事件

这里需要创建QLabel的子类,重写enterEvent和leaveEvent。

注意:要想重写父类的函数,就需要确保这里写的函数名字和函数的参数列表一致(形参名无所谓)

这里要注意,我们通过图形化创建的label是QLabel类的,不是我们创建的子类的实例,我们可以将他提升为Label,也就是我们创建的子类。

此时在看这个控件的类型,可以发现已经变为Label

代码示例: 

label.h

#ifndef LABEL_H
#define LABEL_H
#include <QLabel>
#include <QWidget>

class Label : public QLabel
{
    Q_OBJECT
public:
    Label(QWidget* parent);
    void enterEvent(QEvent* event);
    void leaveEvent(QEvent* event);
};

#endif // LABEL_H

label.cpp

#include "label.h"

#include <QDebug>
Label::Label(QWidget* parent):QLabel(parent)
{

}

void Label::enterEvent(QEvent *event)
{
    (void)event;
    qDebug()<<"enterEvent"<<endl;
}

void Label::leaveEvent(QEvent *event)
{
    (void)event;
    qDebug()<<"leaveEvent"<<endl;
}

效果如下:

鼠标事件

鼠标点击事件

mousePressEvent()用法示例:

void Label::mousePressEvent(QMouseEvent *ev)
{
    //当前event对象就包含了鼠标点击位置的坐标
    qDebug()<<ev->x()<<','<<ev->y();

    qDebug()<<ev->globalX()<<','<<ev->globalY();
}

        这个事件处理的是鼠标点击后,显示鼠标点击位置的坐标, 如下所示,返回两个坐标,但是这两个坐标并不相同,因为 ev->globalX()和ev->globalY()返回的是以屏幕左上角为原点的坐标,x()和y()是以label标签左上角为原点的坐标。

         这里的mousePressEvent不仅是左键点击触发,右键和滚轮点击也可触发,有的鼠标还带有前进后退侧键也是可以触发的。 

         我们有时也要区分用户按了什么按钮,因此可以加上一层判断,如下:

    if(ev->button()==Qt::LeftButton)
    {
        qDebug()<<"按下左键";
    }
    else if(ev->button()==Qt::RightButton)
    {
        qDebug()<<"按下右键";
    }

鼠标释放事件 

mouseReleaseEvent()用法如下:

void Label::mouseReleaseEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::LeftButton)
    {
        qDebug()<<"释放左键";
    }
    else if(ev->button()==Qt::RightButton)
    {
        qDebug()<<"释放右键";
    }
}

鼠标双击事件

如果设置了鼠标单击事件,需要注意逻辑处理,只有第二次按下的时候,才能够识别是双击。双击的同时可能会触发单击事件。

void Label::mouseDoubleClickEvent(QMouseEvent *ev)
{
    if(ev->button()==Qt::LeftButton)
    {
        qDebug()<<"双击左键";
    }
    else if(ev->button()==Qt::RightButton)
    {
        qDebug()<<"双击右键";
    }
}

        上述重写鼠标事件的操作,都是在自定义的label中完成的,此时鼠标只有在label范围进行动作,才能捕获到,也可以把这些操作直接放到Widget(QWidget子类)来完成,这样的话,鼠标在整个窗口中进行的各种动作都能获取到了。

        其中鼠标移动不同于鼠标按下,随便移动下鼠标,就会产生大量的鼠标移动事件,当进行捕获事件的时候,尤其是在进行一些复杂逻辑的时候,程序负担就很重,就很容易产生卡顿的情况,

        Qt为了保证程序的流畅性,默认情况下不会对鼠标移动进行追踪。也就是说鼠标移动的时候,不会调用mouseMoveEvent,除非显式告诉qt追踪鼠标位置。做法如下:

    this->setMouseTracking(true);

鼠标滚轮动作

通过dalta()方法可以或者滚轮滚动的距离。

void Widget::wheelEvent(QWheelEvent *ev)
{
    qDebug()<<ev->delta();
}

键盘事件

要想获取到用户的键盘按键,QShortCut这是信号槽机制封装过,获取键盘按键的方式。站在底层的角度,也可以通过事件获取到当前用户键盘按下的情况。

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_A)
    {
        qDebug()<<"按下了 A 键";
    }
}

上述只是获取单个按键,有时候我们需要获取组合键之类的操作,如下 ctrl + a

void Widget::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_A && event->modifiers() == Qt::ControlModifier)
    {
        qDebug()<<"按下了 ctrl + A 键";
    }
}

定时器事件

QTimer实现了定时器的功能,在QTimer背后是QTimerEvent定时器事件进行支撑的,QObject提供了一个timerEvent这个函数,startTimer 启动定时器,killTimer关闭定时器。

开启定时器事件

int timerId = this->startTimer(1000);

此处的timerId类似于Linux课堂上谈到的“文件描述符”,起到了身份标识的效果。

使用示例:

#include "widget.h"
#include "ui_widget.h"
#include <QWheelEvent>
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    timerId = this->startTimer(1000);
}

Widget::~Widget()
{
    delete ui;
}

void Widget::timerEvent(QTimerEvent *event)
{
    //如果一个程序中存在多个定时器(startTimer 创建的定时器,此时每个定时器都会触发timerEvent函数)
    //先判断以下这次触发是否是想要的定时器触发的
    if(event->timerId() != this->timerId)
    {
        return;
    }
    int value = ui->lcdNumber->intValue();
    if(value <= 0)
    {
        this->killTimer(this->timerId);
        return;
    }
    value-=1;
    ui->lcdNumber->display(value);
}



使用timerEvent比QTimer 还是要更复杂一点,手动管理timerId,还需要区分这次调用是哪个timer引起的。

窗口相关事件

窗口移动触发事件 

moveEvent();

const QPoint & oldpos() const;

const QPoint & pos() const;

示例: 

void Widget::moveEvent(QMoveEvent *event)
{
    qDebug()<<event->oldPos();
    qDebug()<<event->pos();
}


窗口大小改变时触发的事件

resizeEvent();

void Widget::resizeEvent(QResizeEvent *event)
{
    qDebug()<<event->size();
}

扩展

事件分发/事件过滤 属于Qt事件机制背后的一些逻辑,事件分发就是重写event函数,直接获取所有事件,这个后续进行介绍。

  • 32
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值