QT:事件机制

 @[TOC](这里写自定义目录标题)

一、事件机制

qt的核心机制:对象树、信号和槽、事件机制

1.1概念

就是当这件事情发生时,自动执行对应的功能代码。该某块功能代码是虚函数,只需重写该虚函数,即可执行重写的代码。

1.2事件处理简介

1. 什么是事件? (重点)

        事件是由窗口系统或者自身产生的,用以响应所发生的 各类事情,比如用户按下并释放了键盘或>者鼠标、窗口因 暴露而需要重绘、定时器到时而应有所动作,等等。

        从某种意义上讲,事件比信号更原始,甚至可以认为大多 数信号其实都是由事件产生的。比如一个下压式按钮首先 感受到的是鼠标事件, 在进行必要的处理以产生按钮下沉 继而弹起的视觉效果之后,才会发射 clicked()信号。

 2. 如何处理事件? (重点)

     myWnd(自定义类) -继承-> QWidget -继承-> QObject

1> 当事件发生时,首先被调用的是QObject类中的虚函数event(), 其 QEvent型参数标识了具体的事件类型。

bool QObject:: event (QEvent* e)
       {
           if (e == mouseEvent)
           {
               void QWidget::mousePressEvent (QMouseEvent* e)
               void QWidget:: mouseReleaseEvent (QMouseEvent* e)
           }
           if(e == keyEvent){
               void QWidget::keyPressEvent (QMouseEvent* e)
               void QWidget:: keyReleaseEvent (QMouseEvent* e)
           }
       }
  

2> 作为QObject类的子类, QWidget类覆盖了其基类中的 event()虚函数,并根据具体事件调用具体事件处理函数

       void QWidget::mousePressEvent (QMouseEvent* e)
       void QWidget::mouseReleaseEvent (QMouseEvent* e)
       void QWidget::keyPressEvent (QMouseEvent* e)
       void QWidget:: keyReleaseEvent (QMouseEvent* e)
       void QWidget::paintEvent (QPaintEvent* e):

3> 而这些事件处理函数同样也是虚函数,也可以被 QWidget类 的子类覆盖,以提供针对不同窗口部件类型的事件处理

4> 组件的使用者所关心的往往是定义什么样的槽处理什么样的信号, 而组件的实现者更关心覆盖哪些事件处理函数

 1.3 事件处理函数由来

QObject类 提供了哪些可以重写的虚函数:

[virtual] bool QObject::event(QEvent *e) // 参数:事件的类型

QWidgets类, 提供了哪些可以重写的虚函数:

[override virtual protected] bool QWidget::event(QEvent *event)
    
    [virtual protected] void QWidget::keyPressEvent(QKeyEvent *event)
    [virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event)
    [virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mousePressEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event)
    [virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event)
    [virtual protected] void QObject::timerEvent(QTimerEvent *event)

QPainter类 ---> 画家类

 void SimpleExampleWidget::paintEvent(QPaintEvent *)
     {
         QPainter painter(this);
         painter.setPen(Qt::blue);
         painter.setFont(QFont("Arial", 30));
         painter.drawText(rect(), Qt::AlignCenter, "Qt");
     }

 二、定时器事件 QTimerEvent

2.1 作用

让系统每隔一定的时间,自动执行某块功能代码。

2.2 基于事件机制(涉及的函数 )

1、启动定时器

startTimer(int sec); //启动一个定时器,给定毫秒数,返回值是该定时器的id 每隔一定的时间,自动执行timerEvent()函数。

2、关闭定时器

killTimer(int id); //关闭定时器,关闭哪个定时器以id号为准 

3、定时器超时

timerEvent(); //定时器超时时,自动执行的功能代码 --->是QWidget提供的虚函数

 案例

#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    
//    id2 = startTimer(2000);
}

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

//定时器超时时,自动执行的功能函数
void Widget::timerEvent(QTimerEvent *e)
{   
    //判断哪个定时器超时
    if(e->timerId() == id)
    {
        //    static int num =0;
        //    ui->label->setNum(++num);
        
            //获取系统时间
            QTime sys_time = QTime::currentTime();
        
            //将时间转换成字符串
            QString t = sys_time.toString("hh--mm--ss");
        
            //将系统时间放入lab中
            ui->label->setText(t);
        
            //文本居中显示
            ui->label->setAlignment(Qt::AlignCenter);
    }
    
}

//启动按钮对应的槽函数
void Widget::on_pushButton_clicked()
{
    if(ui->pushButton->text() == "启动")
    {
        //启动一个定时器
        id = startTimer(1000); //每隔1秒钟,自动执行timerEvent()函数


        //将文本设置“关闭”
        ui->pushButton->setText("关闭");
    }
    else
    {
         //关闭定时器
         killTimer(id);


        //将文本设置“启动”
        ui->pushButton->setText("启动");
    }
}

2.4 基于属性版本(信号和槽)

  • QTime 时间类
  • QTimeEvent 定时器事件类
  • QTimer 时间事件类

1、使用QTimer类实例化一个对象

2、用该对象调用成员函数 start(int sec); //启动一个定时器,每个一定毫秒,自动触发timeout信号

3、将timeout信号连接到自定的槽函数中

4、用该对象调用成员函数stop(); //关闭定时器

案例

头文件:
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QTime> //时间类
#include<QTimer> //时间事件类
#include<QTimerEvent> //定时器事件类

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    //重写timerEvent()函数的声明
    void timerEvent(QTimerEvent *e);

private slots:
    void on_pushButton_clicked();

    void on_pushButton_2_clicked();

    void timeout_slot();

private:
    Ui::Widget *ui;

    //定义一个定时器的id
    int id;

    // 实例化一个时间事件对象
    QTimer *timer;
};
#endif // WIDGET_H
 源文件:
#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , timer(new QTimer(this)) //给时间事件对象实例化空间
{
    ui->setupUi(this);

    // id2 = startTimer(2000);

    //将系统提供的timeout信号和自定义槽连接
    connect(timer, &QTimer::timeout, this, &Widget::timeout_slot);
}

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

//定时器超时时,自动执行的功能函数
void Widget::timerEvent(QTimerEvent *e)
{
    //判断哪个定时器超时
    if(e->timerId() == id)
    {
        //    static int num =0;
        //    ui->label->setNum(++num);


            //获取系统时间
            QTime sys_time = QTime::currentTime();


            //将时间转换成字符串
            QString t = sys_time.toString("hh--mm--ss");


            //将系统时间放入lab中
            ui->label->setText(t);


            //文本居中显示
            ui->label->setAlignment(Qt::AlignCenter);
    }
}

//启动按钮对应的槽函数
void Widget::on_pushButton_clicked()
{
    if(ui->pushButton->text() == "启动")
    {
        //启动一个定时器
        id = startTimer(1000); //每隔1秒钟,自动执行timerEvent()函数

        //将文本设置“关闭”
        ui->pushButton->setText("关闭");
    }
    else
    {
         //关闭定时器
         killTimer(id);

        //将文本设置“启动”
        ui->pushButton->setText("启动");
    }
}

//启动按钮2对应的槽函数
void Widget::on_pushButton_2_clicked()
{
    if(ui->pushButton_2->text() == "启动")
    {
        //启动一个定时器
        timer->start(1000);//每隔1秒钟,自动出发timeout信号

        //将文本设置“关闭”
        ui->pushButton_2->setText("关闭");
    }
    else
    {
         //关闭定时器
         timer->stop();

        //将文本设置“启动”
        ui->pushButton_2->setText("启动");
    }
}

void Widget::timeout_slot()
{
    //获取系统时间
    QTime sys_time = QTime::currentTime();

    //将时间转换成字符串
    QString t = sys_time.toString("hh--mm--ss");

    //将系统时间放入lab中
    ui->label_2->setText(t);

    //文本居中显示
    ui->label_2->setAlignment(Qt::AlignCenter);
}

 三、键盘事件 QKeyEvent

3.1 概念

当程序员使用键盘(按下,抬起)时,自动执行对应的功能函数。

3.2 重写的功能函数

[virtual protected] void QWidget::keyPressEvent(QKeyEvent *event); //键盘按下事件函数的声明
[virtual protected] void QWidget::keyReleaseEvent(QKeyEvent *event); //键盘抬起事件函数的声明

 3.3 QKeyEvent中常用的函数

int key() const     // 键盘上键对应的键值

QString text() const //键盘上键对应的文本,比如大小写

案例:

Ui界面

 头文件:
#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QKeyEvent> //键盘事件类


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    //键盘按下事件函数的声明
    void keyPressEvent(QKeyEvent *event) override;
    //键盘抬起事件函数的声明
    void keyReleaseEvent(QKeyEvent *event) override;


private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

 源文件:
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}


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


//重写键盘按下事件函数的实现
void Widget::keyPressEvent(QKeyEvent *event)
{
    //qDebug() << "张峪熙不要睡了。。。";

    //ui->label->setText(QString("%1被按下").arg(event->text()));

    QString s = QString("%1被按下").arg(event->text());

    ui->label->setText(s);

    //判断是否是'W'按下 往上跑
    switch (event->key())
    {
        case 'W':
        {
            if(ui->label->y()<0-ui->label->height())
            {
                ui->label->move(ui->label->x(), this->height());
            }
            ui->label->move(ui->label->x(),ui->label->y()-5);
        }
    }
}
//重写键盘抬起事件函数的实现
void Widget::keyReleaseEvent(QKeyEvent *event)
{
    QString s = QString("%1被抬起").arg(event->text());


    ui->label->setText(s);
}

四、鼠标事件 QMouseEvent

4.1 概念

当程序员使用鼠标时,自动执行对应的功能函数。

4.2 重写的功能函数

[virtual protected] void QWidget::mouseDoubleClickEvent(QMouseEvent *event);//鼠标双击事件函数
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event);//鼠标移动事件函数
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);//鼠标按下事件函数
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);//鼠标抬起事件函数

4.3 QMouseEvent中常用的函数

button()  ------>使用鼠标时,该函数判断哪个键被按下
buttons() ------>针对于鼠标移动时,判断哪个键被按下
pos()    -------->当前鼠标所在的位置
globalPos()  ------->鼠标针对于全局的坐标点
x()   ------->x坐标点
y()   ------->y坐标点

案例:

头文件:
#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QKeyEvent> //键盘事件类
#include<QMouseEvent> //鼠标事件类


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void mousePressEvent(QMouseEvent *event) override;//鼠标按下事件函数声明
    void mouseReleaseEvent(QMouseEvent *event) override;//鼠标抬起事件函数声明
    void mouseDoubleClickEvent(QMouseEvent *event) override;//鼠标双击事件函数声明
    void mouseMoveEvent(QMouseEvent *event) override;//鼠标移动事件函数声明

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H
源文件:
#include "widget.h"
#include "ui_widget.h"
#include<QDebug>


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //开启鼠标追踪功能
    this->setMouseTracking(true);
}

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

//重写鼠标按下事件函数实现
void Widget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        ui->label->setText(QString("左键被按下(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::RightButton)
    {
        ui->label->setText(QString("右键被按下(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::MidButton)
    {
        ui->label->setText(QString("中间键被按下(%1,%2)").arg(event->x()).arg(event->y()));
    }
}
//重写鼠标抬起事件函数实现
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        ui->label->setText(QString("左键被抬起(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::RightButton)
    {
        ui->label->setText(QString("右键被抬起(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::MidButton)
    {
        ui->label->setText(QString("中间键被抬起(%1,%2)").arg(event->x()).arg(event->y()));
    }
}
//重写鼠标双击事件函数实现
void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        ui->label->setText(QString("左键被双击(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::RightButton)
    {
        ui->label->setText(QString("右键被双击(%1,%2)").arg(event->x()).arg(event->y()));
    }
    else if(event->button() == Qt::MidButton)
    {
        ui->label->setText(QString("中间键被双击(%1,%2)").arg(event->x()).arg(event->y()));
    }
}
//重写鼠标移动事件函数实现
void Widget::mouseMoveEvent(QMouseEvent *event)
{
    ui->label->move(event->pos());
}

纯净窗口的移动

头文件:

#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include<QMouseEvent> //鼠标事件类
#include<QPoint> //向量类


QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE


class Widget : public QWidget
{
    Q_OBJECT


public:
    Widget(QWidget *parent = nullptr);
    ~Widget();


    void mouseMoveEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;


private:
    Ui::Widget *ui;


    QPoint p; //记录鼠标在当前窗口的位置
};
#endif // WIDGET_H

源文件:

#include "widget.h"
#include "ui_widget.h"


Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);


    //设置纯净窗口
    this->setWindowFlag(Qt::FramelessWindowHint);
}


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


void Widget::mouseMoveEvent(QMouseEvent *event)
{
    //判断是否是左键被按下
    if(event->buttons() == Qt::LeftButton)
    {


        //窗口移动
        this->move(event->globalPos() - p);
                     //全局坐标         当前窗口坐标


    }


}
void Widget::mousePressEvent(QMouseEvent *event)
{
    p = event->pos(); //鼠标在当前窗口的坐标
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值