QT第五课------QT系统相关------Event

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言、C++和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


介绍

前面我们学习的很多控件,知道QT是跨平台一个c++开发的框架,QT的很多功能是由操作系统提供的,是因为QT封装了系统的API,每个系统有对于的API,
程序运行在操作系统, 需要我们理解操作系统

Qt 事件

前面我们学习信号槽,知道用户进行操作的时候,会触发信号,我们可以给这些信号设置槽函数
而事件与其相似, 用户进行操作也会发生事件,也可以给其关联上对应的函数
事件是操作系统提供的机制, 而Qt把操作系统的事件机制进行了封装,得到了信号槽
进而可以理解, 事件机制是信号槽的底层机制,而信号槽是事件机制的封装
但是在一些事件中,QT没有提供对于的信号函数, 需要我们重写事件处理函数的形式,来处理事件的响应逻辑

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

的 Qt 事件如下:在这里插入图片描述
对于的为如下:
⿏标事件: ⿏标左键、⿏标右键、⿏标滚轮,⿏标的移动,⿏标按键的按下和松开
键盘事件 :按键类型、按键按下、按键松开
定时器事件: 定时时间到达
进⼊离开事件: ⿏标的进⼊和离开
滚轮事件 :⿏标滚轮滚动
绘屏事件 :重绘屏幕的某些部分

点击事件处理

下面我们写一个鼠标进入控件和出来的代码,下面需要我们重写一下虚函数
在实现⿏标的进⼊和离开事件时,直接重新实现 enterEvent() 和 leaveEvent(),原型如下:
在这里插入图片描述
在这里插入图片描述
我们需要创建一个类,用来演示鼠标进入标签和出来表现,
label.h

#include <QObject>
#include <QWidget>
#include<QLabel>

struct Label : QLabel
{
    Q_OBJECT
public:
    Label(const QString& , QWidget * parent = nullptr);
    virtual void enterEvent(QEvent *event);
    virtual void leaveEvent(QEvent *event);
};

label.cpp

Label::Label(const QString& name, QWidget * parent)
    :QLabel(name,parent)

{


}

void Label::enterEvent(QEvent *event)
{
    QLabel::enterEvent(event);
    qDebug()<< "enter";

}

void Label::leaveEvent(QEvent *event)
{
    QLabel::leaveEvent(event);
    qDebug()<< "leave";

}

mainwidget.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //设置中心窗口
    QWidget * w = centralWidget();
    setCentralWidget(w);
    QVBoxLayout * verticalLayout = new QVBoxLayout();
    QString name("这是一个标签");
    QLabel * label = new Label(name);
    label->setFrameShape(QFrame::Box);

    verticalLayout->addWidget(label);
    verticalLayout->addWidget(new QPushButton("按钮"));

    w->setLayout(verticalLayout);
}

效果图:
在这里插入图片描述
接下来我们重写一下mousePressEvent()函数,这是一个点击函数,当点击标签的时候,就会获取到对应的坐标

void Label::mousePressEvent(QMouseEvent *ev)
{
    QLabel::mousePressEvent(ev);
    qDebug()<< QString("位置为(%1,%2)").arg(ev->x()).arg(ev->y());
}

效果:
在这里插入图片描述
可以看到,QMouseEvent这个类对应的就是Event的子类, 也就是点击的坐标类
x(),y()函数只是获取到相对位置的坐标,如果使用的是globalX(),获取到的就是以电脑屏幕左上角为原点的坐标了

鼠标键类型

除了可以获取坐标,还可以进行判断鼠标点击的是哪个按钮, 这样我们就可以判断一些事件
代码如下:

if(ev->button() == Qt::LeftButton)
        qDebug()<< "左键";

释放事件

前面我们还知道.一个鼠标的clicked包含有按下和释放,上面我们只是重写了鼠标的点击,没有重写分释放
下面我们重写一个释放的虚函数mouseReleaseEvent()

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

}

双击事件

我们日常也会使用很多双击的情况, 需要注意的是,双击的判断是第一次clicked(包含点击和释放)且第二次点击没有释放的,
下面我们重写一个双击鼠标的虚函数mouseDublie()

void Label::mouseDoubleClickEvent(QMouseEvent *event)
{
    (void)event;
     qDebug()<< "双击";
}

鼠标移动

上面我们重写的虚函数都是在QLabel的子类中进行的,捕获到的信息也只是在其子类中的,如果我们想要在QWidget的子类进行,只需在widget类中进行虚函数重写
而在鼠标移动这里,不仅仅要重写,归其原因就是,鼠标在移动的过程会产生大量的鼠标移动事件,如果再进行复杂逻辑的操作,就会给程序造成很大的负担,Qt为了保证流畅性,不会直接追踪鼠标位置, 需要我们把etMouseTracking() 函数默认是 false,需要设置为 true,才能实时捕获⿏标位置信息。否则只有当⿏标按下时才能捕获其位置信息。

 setMouseTracking(true);//设置设置鼠标捕获
void Label::mouseMoveEvent(QMouseEvent *event)
{


    qDebug()<< event->x()<< event->y();

}

效果如下:
在这里插入图片描述
需要注意的是,只有把setMouseTracking设置为true才会调用对应函数,

鼠标滚轮

在 Qt 中,⿏标滚轮事件是通过 QWheelEvent 类来实现的。滚轮滑动的距离可以通过 delta() 函数获
取。delta() 函数原型如下:
int QGraphicsSceneWheelEvent::delta() const
其中返回值代表滚轮滑动的距离。正数表⽰滚轮相对于⽤⼾向前滑动,负数表⽰滚轮相对于⽤⼾向后
滑动。
下面我们重写一下虚函数wheelEvent()

void Label::wheelEvent(QWheelEvent *event)
{
    //获取到当前滚轮的移动距离
    qDebug()<<event->delta();

}

需要注意的是delta()不会统计总的滚动距离,只会返回滚动方向的距离,如图:
在这里插入图片描述
这个图就是每次滚动鼠标滚轮的距离

按键事件

上面的代码们只要我们点击按键,就会直接输出出来,但是我们不能知道按下的是哪个按键,
Qt 中的按键事件是通过 QKeyEvent 类来实现的。当键盘上的按键被按下或者被释放时,键盘事件便会触发。在帮助⽂档中查找 QKeyEvent 类如下:
在这里插入图片描述
下面我们需要重写一个keypreeEvent()函数,用来判断按下的按键是哪个, 函数原型如下:
在这里插入图片描述
下面我们进行简单的重写

void Label::keyPressEvent(QKeyEvent *ev)
{
    //输出按键
    qDebug()<< ev->key();

}

如果只是这样去设置,当我们运行按下的时候,是没有输出的因为,如果你的窗口中有其他控件(如按钮、文本框等),它们可能会拦截键盘事件。可以通过设置 setFocusPolicy(Qt::StrongFocus) 来确保你的窗口能够接收键盘事件。

 setFocusPolicy(Qt::StrongFocus)

组合键

有些时候,我们会按下一些比如Alt+a这样的组合键,上面的代码不会满足, 在Qt中就有了Qt::KeyboardModifier
在这里插入图片描述
下面我们进一步修改一下重写的虚函数

void Label::keyPressEvent(QKeyEvent *ev)
{
    //输出按键

    //判断是否是输入了组合键
    if(ev->key()&& ev->modifiers())
           qDebug()<< QString("按下组合键%1和%2").arg(ev->key()).arg(ev->modifiers());
    else
         qDebug()<< QString("按下单键%1").arg(ev->key());

}

这样如果我们按下双键就会被捕获到,

定时器事件

Qt中的定时器分为 QTimerEvent 和 QTimer 这2个类。
QTimerEvent类 ⽤来描述⼀个定时器事件。在使⽤时需要通过 startTimer() 函数来开启⼀个定时
器,这个函数需要输⼊⼀个以毫秒为单位的整数作为参数来表明设定的时间循环触发
,它返回的整型值代表
这个定时器。当定时器溢出时(即定时时间到达)就可以在 timerEvent() 函数中获取该定时器的
编号来进⾏相关操作。
QTimer类 来实现⼀个定时器,它提供了更⾼层次的编程接⼝,如:可以使⽤信号和槽,还可以设
置只运⾏⼀次的定时器。
前面我们写过QTimer的定时器显示文章可以查看,里面

QTimerEvent类

下面我们写一个简单的代码
需要我们重写一下timerEven(), 这函数就是在该控件范围内,当设置定时器并且定时器被触发的时候, 就会执行该函数,如果有多个定时器,每个定时器都会触发这个函数, 所以,我们使用这个QTimerEvent类的话,需要在这个重写函数里面进行判断哪个定时器执行这个函数
代码如下:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //
   QWidget * window=  centralWidget();
   setCentralWidget(window);
   //创建一个标签
   QLabel * label = new QLabel("下面为定时器的演示");
   //创建一个布局
   QVBoxLayout * veriticallayout = new QVBoxLayout();
   window->setLayout(veriticallayout);
   veriticallayout->addWidget(label,5);
   label->setFrameShape(QFrame::Box);
   //创建一个LCD number
   numberBox = new QLCDNumber();
   numberBox->display(0);
   numberBox->resize(20,20);
   veriticallayout->addWidget(numberBox,1);
   //设置空间布局的尽可能占据
   label->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
   numberBox->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
   //设置定时器
   timeId = startTimer(1000);//1000ms执行一次这行,返回一个定时器的身份标识





}

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

void MainWindow::timerEvent(QTimerEvent *event)
{
    if(timeId == event->timerId())
    {
        //获取LCD的值,并添加1
        numberBox->display(numberBox->value()+1);
    }
    qDebug()<<"1";
    if(numberBox->value() == 30)
        killTimer(timeId);

}

效果如下:
在这里插入图片描述

如果要杀死定时器可以使用killTimer()函数杀死
可以看到使用TimerEvent这个类,会更复杂一些,需要进行判断是哪个定时器触发timerEvent函数,而使用Timer不会,所以实际开发使用Timer

moveEvent和resizeEvent

这两个函数,一个是移动位置的函数,一个控件大小的函数,下面使用一个新的Qwidget的子类进行演示

void MainWindow::resizeEvent(QResizeEvent *event)
{
    qDebug()<< "旧的大小"<<event->oldSize();
    qDebug()<< "新的大小"<<event->size();
}

void MainWindow::moveEvent(QMoveEvent *event)
{
    qDebug()<< "旧的位置"<<event->oldPos();
    qDebug()<< "新的位置"<<event->pos();
}

这里涉及到两个类,如上面的代码,

事件分发器

在Qt中,发送的事件都是传给了 QObject 对象,更具体点是传给了 QObject 对象的 event() 函
数。所有的事件都会进⼊到这个函数⾥⾯,那么我们处理事件就要重写这个 event() 函数。event() 函
数本⾝不会去处理事件,⽽是根据 事件类型(type值)调⽤不同的事件处理函数。事件分发器就是⼯
作在应⽤程序向下分发事件的过程中,简单的理解就是,event函数,会获取到所有的事件,比如用户点击了鼠标,就会触发mousePreeEvent这个事件函数, 具体一些就是,用户点击鼠标的时候,会先调用event这个事件分发器函数,然后再调用对于函数,
如图:
在这里插入图片描述

在Qt中,事件的封装是在QEvent类中的,其中type的枚举如下:
在这里插入图片描述
下面我们写一个简单的代码进行

创建了一个类widget, 用来提升centralwidget,
widget.h

widget::widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::widget)
{
    ui->setupUi(this);
     setFocusPolicy(Qt::StrongFocus);
}

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

void widget::mousePressEvent(QMouseEvent *event)
{
    qDebug()<< "点击鼠标了";
}
bool widget::event(QEvent *event)
{
    if(event->type() == QEvent::MouseButtonPress)
    {
        qDebug()<<"被拦截了鼠标点击";
        return true;
    }
    qDebug()<<"触发其他事件";
    return false;
}

如图:
在这里插入图片描述

这里重写了event函数, event函数会获取到所有的事件,也可以拦截所有的事件,具体需要看个人

事件过滤器

上面我们知道使用event()拦截事件,会很不好,因为要写多个或者写的时候要小心, 为此Qt提供了一个事件过滤器,
在事件发送给事件分发器的时候进行拦截, 这样就可以少写很多的代码了
如下图:
在这里插入图片描述
如果要实现过滤器据需要我们进行下面两步
1、安装事件过滤器;installfilter()
2、重写事件过滤器函数:eventfilter() 。
我们可以理解过滤器是需要我们添加的而event是自动的,就很好记忆了
借用上面的代码,我们直接给widget添加一个事件过滤器,然后重写eventfilter函数

widget::widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::widget)
{
    ui->setupUi(this);
     setFocusPolicy(Qt::StrongFocus);//设置焦点的
     //安装事件过滤器
     installEventFilter(this);
}

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

void widget::mousePressEvent(QMouseEvent *event)
{
    qDebug()<< "点击鼠标了";
}

bool widget::eventFilter(QObject *watched, QEvent *event)
{
    if(watched == this)//直接拦截所有的事件
    {
        if(event->type() == QEvent::MouseButtonPress)//设置鼠标按键拦截
        {
            qDebug()<<"事件过滤器拦截";
            return true;
         }
    }
    return QWidget::eventFilter(watched, event);
}
bool widget::event(QEvent *event)
{
    if(event->type() == QEvent::MouseButtonPress)
    {
        qDebug()<<"被拦截了鼠标点击";
        return true;
    }
    qDebug()<<"触发其他事件";
    return false;
}

效果图:
在这里插入图片描述
可以看出过滤器生效了,拦截了鼠标点击事件发送给event()(分发器)

总结
过滤器和分发器是为了处理控件的事件, 一个控件可以发生很多的事件,然后五幺我们进行对这些事件的处理, 进而演变成我们进行对应的重写操作, 这样我们就会很好的记忆, 不会混乱,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老秦包你会

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值