Qt中的事件

1、自定义控件 提供外部接口

form.h的类中声明

#ifndef FORM_H
#define FORM_H

#include <QWidget>

namespace Ui {
class Form;
}

class Form : public QWidget
{
    Q_OBJECT

public:
    explicit Form(QWidget *parent = 0);
    //提供设置slider的value接口
    void mySetValue(int value);
    //提供获取slider的value接口
    int myGetValue();
    ~Form();

private:
    Ui::Form *ui;
};

#endif // FORM_H

form.cpp

#include "form.h"
#include "ui_form.h"

Form::Form(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Form)
{
    ui->setupUi(this);
    void (QSpinBox::*p)(int i) = &QSpinBox::valueChanged;
    connect(ui->spinBox,p,ui->horizontalSlider,&QSlider::setValue);
    connect(ui->horizontalSlider,&QSlider::valueChanged,ui->spinBox,&QSpinBox::setValue);

}

void Form::mySetValue(int value)
{
    //设置进度条slider的值
    ui->horizontalSlider->setValue(value);
}

int Form::myGetValue()
{
    //获取进度条的值
    return ui->horizontalSlider->value();
}

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

mywindow.cpp的构造函数

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <form.h>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //单击button 设置一半
    connect(ui->pushButton,&QPushButton::clicked,[=](){
        ui->widget->mySetValue(50);
    });

    //单击button 获取进度条的值
    connect(ui->pushButton_2,&QPushButton::clicked,[=](){
        qDebug() << ui->widget->myGetValue() << endl;
    });



}

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

运行结果:
在这里插入图片描述

2、事件的概述

Qt 中所有事件类都继承于QEvent。在事件对象创建完毕后,Qt 将这个事件对象传递给QObject的event()函数。event()函数并不直接处理事件,而是按照事件对象的类型分派给特定的事件处理函数(event handler),关于这一点,会在后边详细说明。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用户如果使用该事件,由于事件函数是virtual必须用户实现

3、通过QLabel了解事件的操作

在这里插入图片描述
在这里插入图片描述
如果重写QLabel事件,需要在自定义的label控件中实现时间的重写
在这里插入图片描述
在这里插入图片描述
在mylabel.h中修改如下:
在这里插入图片描述

#ifndef MYLABEL_H
#define MYLABEL_H

#include <QLabel>

class MyLabel : public QLabel
{
    Q_OBJECT
public:
    explicit MyLabel(QWidget *parent = 0);

signals:

public slots:
};

#endif // MYLABEL_H

在mylabel.cpp修改如下:
在这里插入图片描述

#include "mylabel.h"

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{

}

在这里插入图片描述
提升label的类型为MyLabel
在这里插入图片描述
在这里插入图片描述

总结:如果像重写某个类的事件,一般情况就要自定义一个类继承于该控件的类型,然后将控件的类提升成自定义的类,这样我们就可以在自定义类中重写控件类型时间函数。

重写事件:

事件资料:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
mylabel.h:
在这里插入图片描述
在这里插入图片描述
运行结果:
在这里插入图片描述
重写鼠标按下事件:
在这里插入图片描述
mylabel.h:
在这里插入图片描述
获取鼠标按下或移动的坐标:
在这里插入图片描述查看QMouseEvent的信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
判断button的返回值:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
判断鼠标的哪个按键按下:

void MyLabel::mousePressEvent(QMouseEvent *ev)
{
    //ev包含了我们所需要的坐标信息
    if(ev->button() == Qt::LeftButton){
        qDebug() << "鼠标左键按下了" << endl;
    }else if(ev->button() == Qt::RightButton){
         qDebug() << "鼠标右键按下了" << endl;
    }

}

运行结果:
在这里插入图片描述
判断鼠标的坐标:

void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    if(ev->button() == Qt::LeftButton){

    }
    qDebug() << "鼠标移动了 x = " << ev->x() << ",y ="<< ev->y()<< endl;
}

运行结果:
在这里插入图片描述
鼠标跟踪:(用户不用按下鼠标 也可以获得鼠标移动位置,在QWidget中public functions中找到)

#include "mylabel.h"
#include <QDebug>
#include <QMouseEvent>
MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
    this->setMouseTracking(true);
}

void MyLabel::enterEvent(QEvent *event)
{
    qDebug() << "鼠标进入了" << endl;
}

void MyLabel::leaveEvent(QEvent *event)
{
    qDebug() << "鼠标离开了" << endl;
}

void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    if(ev->button() == Qt::LeftButton){

    }
    qDebug() << "鼠标移动了 x = " << ev->x() << ",y ="<< ev->y()<< endl;
}

void MyLabel::mousePressEvent(QMouseEvent *ev)
{
    //ev包含了我们所需要的坐标信息
    if(ev->button() == Qt::LeftButton){
        qDebug() << "鼠标左键按下了" << endl;
    }else if(ev->button() == Qt::RightButton){
         qDebug() << "鼠标右键按下了" << endl;
    }

}

运行结果:
在这里插入图片描述

4、事件分发器

事件对象创建完毕后,Qt将对这个事件对象传递给QObject的event()的函数。event()函数并不直接处理事件,而是将这些事件按照不同的类型,分发给不同事件处理器(event hanler).
event()函数主要用于事件的分发
在这里插入图片描述
如果你希望在事件分发之前作一些操作,就可以重写这个event()函数了
1、如果传入的事件已被识别并且处理,则需要返回true,否则返回false。如果返回值是true,那么Qt会认为这个事件已经处理完毕,不会再将这个事件发送给其他对象,而是会继续处理事件队列中的下一事件。
2、在event()函数中,调用事件对象的accept()和ignore()函数是没有作呕用的,不会影响到事件的传播。
3、不关心的事件,记得用父类的事件分发器进行处理
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
案件:在事件分发器中,处理鼠标单击事件
1、重写分发器事件(MyLabel)

virtual bool event(QEvent *e)

2、判断初始鼠标单击:
在这里插入图片描述
3、mylabel.h中重写事件分发器

//事件分发器,e存放具体的事件
bool MyLabel::event(QEvent *e)
{
    //只关心鼠标按下事件
    if(e->type() == QEvent::MouseButtonPress){
        qDebug() << "在事件分发器中鼠标单击了" << endl;
        //注意:QEvent没有x,y
        QMouseEvent *ev = (QMouseEvent *)e;
        qDebug() << "x ="<< ev->x() << ",y ="<< ev->y()<< endl;
        return true;
    }
    //请调用父类的QLabel的event处理其它事件
    return QLabel::event(e);
}

在这里插入图片描述

2、重写事件过滤器

通过前面的章节,我们已经知道,Qt 创建了QEvent事件对象之后,会调用QObject的event()函数处理事件的分发。显然,我们可以在event()函数中实现拦截的操作。由于event()函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当麻烦,更不用说重写event()函数还得小心一堆问题。好在 Qt 提供了另外一种机制来达到这一目的:事件过滤器
在这里插入图片描述
不想让他继续转发,就返回true,否则返回false
在QObject类中Public Functions找到:
在这里插入图片描述
1、在MyLabel.cpp的构造函数中加载事件过滤器
在这里插入图片描述
2、重写事件过滤器
在mylabel.h中声明事件过滤器函数
在这里插入图片描述
在mylabel.cpp中实现 事件过滤器函数
在这里插入图片描述

运行结果:
在这里插入图片描述
注意:
1、这种全局的事件过滤器将会在所有其它特性对象的事件过滤器之前调用。尽管很强大,但这种行为严重降低整个应用程序的事件分发效率。
2、事件过滤器和被安装过滤器的组件必须在同一线程,否则,过滤器将不起作用。另外,如果在安装过滤器之后,这两哥组件到了不同的线程,那么,只有等到二者重新回到同一线程的时候过滤器才会有效。

5、定时器—QTimer控件

三种定时器触发方式

1、定时器事件触发

在这里插入图片描述
在这里插入图片描述
启动定时器
在这里插入图片描述
在这里插入图片描述

2、定时器对象触发

3、静态成员函数

案例1:定时器事件
QObject中的定时器的使用,需要用到三个函数

int QObject::startTimer ( int interval ) ;

这个是开启一个定时器的函数,他的参数interval是毫秒级别。当开启成功后会返回这个定时器的ID, 并且每隔interval 时间后会进入timerEvent 函数。直到定时器被杀死。

void QObject::timerEvent ( QTimerEvent * event );

当定时器超时后,会进入该事件timerEvent函数,需要重写timerEvent函数,在函数中通过判断event->timerId()来确定定时器,然后执行某个定时器的超时函数

void QObject::killTimer ( int id );

通过从startTimer返回的ID传入killTimer 函数中杀死定时器,结束定时器进入超时处理。

所有QObject的子类都具有定时器的功能
在mainwindow.h中:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    //重写定时器事件
    virtual void timerEvent(QTimerEvent *e);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

在mainwindow.cpp中:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

int MainWindow::id = 0;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //启动定时器事件
    int m = this->startTimer(1000);
}
//重写定时器分发事件
void MainWindow::timerEvent(QTimerEvent *e)
{
    static int time = 0;
    id++;
    //将计数结果在在界面显示
    ui->label_2->setText(QString::number(time++));
    //在计数次数超过20次时,中断计数
    if(id > 20){
        this->killTimer(e->timerId());
    }
}

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

void MainWindow::on_pushButton_clicked()
{
     qDebug() << "鼠标进入了" << endl;
}

运行结果:
在这里插入图片描述
案例2:同时启动多个计时器
在这里插入图片描述
mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    static int id;
    explicit MainWindow(QWidget *parent = 0);
    //重写定时器事件
    virtual void timerEvent(QTimerEvent *e);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    int id1;
    int id2;
};

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

int MainWindow::id = 0;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //启动定时器事件
    id1 = this->startTimer(1000);
    id2 = this->startTimer(2000);
}
//重写定时器分发事件
void MainWindow::timerEvent(QTimerEvent *e)
{
    static int time1 = 0;
    static int time2 = 0;
    //id++;
    if(e->timerId() == id1){
        //将计数结果在在界面显示
        ui->label_2->setText(QString::number(++time1));
    }else if(e->timerId() == id2){
        ui->label_3->setText(QString::number(++time2));
    }
}

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

void MainWindow::on_pushButton_clicked()
{
     qDebug() << "鼠标进入了" << endl;
}

运行结果:
在这里插入图片描述
案例3:通过定时器对象定时
mainwindow.h:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QTimer>
#include <QMainWindow>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    static int id;
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private slots:
    void on_pushButton_clicked();
    void on_pushButton_2_clicked();
private:
    Ui::MainWindow *ui;
    int id1;
    int id2;
    //定义一个定时器对象
    QTimer *t;
};
#endif // MAINWINDOW_H

mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QTimer>

int MainWindow::id = 0;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //实例化QTimer对象
    t = new QTimer(this);
    static int time2 = 0;
    //timeout()为信号函数,定时器超时函数,每超过定时器定义时间,该信号函数执行
    connect(t,&QTimer::timeout,[=](){
         ui->label_3->setText(QString::number(++time2));
    });
}

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

void MainWindow::on_pushButton_clicked()
{
    //启动定时器
    //时间间隔为100ms
    //每隔1000ms,定时器myTimer自动触发timeout()
    //如果定时器没有激活,才启动,防止多次点击start按钮出现错误
    if(t->isActive() == false){
        t->start(1000);
    }    
}

void MainWindow::on_pushButton_2_clicked()
{
    //暂停定时器
    if(t->isActive() == true){
        t->stop();
    }    
}

运行结果:
在这里插入图片描述
案例4:通过静态成员函数singleShot 实现延时的功能
在这里插入图片描述
mainwindow.cpp:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
//#include <QTimer>

int MainWindow::id = 0;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //实例化QTimer对象
    t = new QTimer(this);
    static int time2 = 0;
    //timeout()为信号函数,定时器超时函数,每超过定时器定义时间,该信号函数执行
    connect(t,&QTimer::timeout,[=](){
         ui->label_3->setText(QString::number(++time2));
    });
    QTimer::singleShot(5000,[=](){
        ui->label_4->setText("哈哈,我喜欢你");
    });
}

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

void MainWindow::on_pushButton_clicked()
{
    //启动定时器
    //时间间隔为100ms
    //每隔1000ms,定时器myTimer自动触发timeout()
    //如果定时器没有激活,才启动,防止多次点击start按钮出现错误
    if(t->isActive() == false){
        t->start(1000);
    }
}

void MainWindow::on_pushButton_2_clicked()
{
    //暂停定时器
    if(t->isActive() == true){
        t->stop();
    }
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值