QT:事件机制

news2025/2/6 1:05:35

一、事件机制

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(); //鼠标在当前窗口的坐标
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2056600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

algorithm算法库学习之——堆操作,最小/最大操作,比较操作,排列操作

algorithm此头文件是算法库的一部分。本篇介绍堆操作&#xff0c;最小/最大操作&#xff0c;比较操作&#xff0c;排列操作。 接口API 堆操作 is_heap 检查给定范围是否为一个最大堆 (函数模板) is_heap_until (C11) 查找能成为最大堆的最大子范围 (函数模板) make_heap 从一…

SQL 时间盲注 (injection 第十六关)

简介 SQL注入&#xff08;SQL Injection&#xff09;是一种常见的网络攻击方式&#xff0c;通过向SQL查询中插入恶意的SQL代码&#xff0c;攻击者可以操控数据库&#xff0c;SQL注入是一种代码注入攻击&#xff0c;其中攻击者将恶意的SQL代码插入到应用程序的输入字段中&#x…

C:每日一题:双指针法的使用

前言&#xff1a; 思虑再三&#xff0c;觉得如果有时间每日一题还是可以更新一下的。 题目难度&#xff1a;基础 解题方法&#xff1a;双指针法 一、题目 输入一个整数数组&#xff0c; 实现一个函数来调整该数组中数字的顺序使得 数组中所有的奇数位于数组的前半部分&a…

数字人的形象克隆与语音克隆是伪需求

形象克隆与语音克隆技术&#xff0c;在当前的环境上已经可以成熟的实现&#xff0c;但真的解决了痛点问题吗&#xff1f; 普通人或者一般的公司克隆自己内部人的形象有必要吗&#xff1f;对外界而言&#xff0c;克隆的形象与虚拟的形象并无二致&#xff0c;本身并没有什么知名…

Arduino自制手持小风扇项目

1.1 介绍&#xff1a; 实验功能说明&#xff1a;功能&#xff08;1&#xff09;按一下按键小风扇开启&#xff0c;再按一下关闭。 功能&#xff08;2&#xff09;按一下按键小风扇一档风速&#xff0c;再按一下二挡&#xff0c;依次三挡…关闭。 按键模块说明&#xff1a;按下…

【自动化测试必学语言】python:模块和包

目录 导入模块的语法 方式一 方式二 方式三 【了解】 基本不用 模块的查找顺序 __name__ 的作用 代码练习 包(package) Python 源代码文件就是⼀个模块模块中定义的变量函数类&#xff0c;都可以让别人使用&#xff0c;同样&#xff0c;可以使用别人定义的&#xff08…

进程(2) wait、exec函数族

目录 1. fork() 函数 功能 使用时注意事项 2. exit() 函数 功能 使用时注意事项 3. wait() 函数 功能 使用时注意事项 总结 wait() 异常信号结束 waitpid exec函数族 execl() execlp() execv execvp fork()、exit() 和 wait() 函数在进程管理中扮演着重要的角…

【C语言】【Linux】如何在Linux终端中进行彩色输出——C语言篇

&#x1f41a;作者简介&#xff1a;花神庙码农&#xff08;专注于Linux、WLAN、TCP/IP、Python等技术方向&#xff09;&#x1f433;博客主页&#xff1a;花神庙码农 &#xff0c;地址&#xff1a;https://blog.csdn.net/qxhgd&#x1f310;系列专栏&#xff1a;C语言编程&…

双亲委派机制的优势与劣势

三次双亲委派机制的破坏

24 优化算法

目录 优化和深度学习深度学习中的挑战局部最小 vs 全局最小鞍点(saddle point)梯度消失小结凸性(convexity)凸集凸函数(convex function)凸函数优化凸和非凸例子小结梯度下降(gradient descent)1、梯度下降算法是最简单的迭代求解算法2、学习率(learning rate)小结随…

Unity小功能 - 贴墙滑行

目录 一. 简介 二. 创建项目 1.新建地板 2.创建墙体 3.创建主角 三. 编写代码 四. 效果演示 五. 总结 一. 简介 贴墙滑行是在游戏中常见的一种角色动作表现&#xff0c;它能够增加游戏的真实感和趣味性&#xff0c;同时也为游戏玩法带来更多的可能性。 在 Unity 中实…

【秋招笔试】8.18大疆秋招(第三套)-三语言题解

🍭 大家好这里是 春秋招笔试突围,一起备战大厂笔试 💻 ACM金牌团队🏅️ | 多次AK大厂笔试 | 编程一对一辅导 ✨ 本系列打算持续跟新 春秋招笔试题 👏 感谢大家的订阅➕ 和 喜欢💗 和 手里的小花花🌸 ✨ 笔试合集传送们 -> 🧷春秋招笔试合集 🍒 本专栏已收…

测绘程序设计|测绘程序设计大赛介绍|备赛建议

**由于微信公众号改变了推送规则&#xff0c;为了每次新的推送可以在第一时间出现在您的订阅列表中&#xff0c;记得将本公众号设为星标或置顶喔~** 简单介绍测绘学科创新创业智能大赛测绘技能竞赛——测绘程序设计比赛。 &#x1f33f;前言 测绘程序设计比赛是测绘学科创新创…

HTTPS协议和HTTP协议的区别详细图解

文章目录 HTTPS协议加密是什么&#xff1f;对称加密非对称加密 Cookie 和 Session的区别 HTTPS协议 HTTP协议内容都是按照文本的方式明文传输的&#xff0c;是没有经过加密的&#xff0c;没有加密就意味着裸奔&#xff0c;所以协议中的内容就很容易引起一些不良人士的获取和篡…

STM32自制手持小风扇实验

1.1 介绍&#xff1a; 实验功能说明&#xff1a;功能&#xff08;1&#xff09;按一下按键小风扇开启&#xff0c;再按一下关闭。 功能&#xff08;2&#xff09;按一下按键小风扇一档风速&#xff0c;再按一下二挡&#xff0c;依次三挡…关闭。 按键模块说明&#xff1a;按下…

CommandLineRunner

CommandLineRunner 是 Spring Boot 中的一个接口&#xff0c;它允许你在 Spring 应用程序启动之后&#xff08;即在 SpringApplication.run() 执行完成后&#xff09;立即执行一些代码。这在你需要初始化数据、检查配置文件参数或执行其他启动任务时非常有用。 实现 CommandLin…

win10蓝屏CRITICAL_PROCESS_DIED

目录 前言 处理过程 第一阶段处理&#xff1a;重置虚拟内存 第二阶段处理&#xff1a;sfc /scannow 扫描系统并修复损坏文件 前言 连续一周开机一段时间后蓝屏&#xff0c;刚开始的蓝屏提示的是KERNEL_DATA_INPAGE_ERROR&#xff0c;后来经过一番操作&#xff0c;依然出现…

vue使用axios请求后端数据

前后端分离项目的基础&#xff1a; 前后端跨域访问 vite.config.js中加入 // 1.为什么要跨域 //因为浏览器的同源策略,不同站点之间访问需要跨域 //实现跨域的方式&#xff1a;server: {proxy: {// 假设要跨域访问的后端 API 地址以 /api 开头/api: { //表示拦截以/api开头的…

牛客算法小题

目录 牛客.求和​编辑 牛客.abb 牛客.合并k个有序链表 牛客.滑雪&#xff08;暴力->递归->记忆化搜索&#xff09; 牛客.旋转字符串 牛客.求和 我没想到是dfs&#xff0c;另外我的dfs能力确实也不强&#xff0c;另外难度大的是他的那个输出 import java.util.Scanne…

医用氧检测标准:医用氧用什么检怎么检都做了明确规定

新规在《中国药典》2020 年版二部 XGB2021-061条于2022年5月22日实施。 医用氧技术指标&#xff1a;氧≥99.5% 、一氧化碳<0.0005、二氧化碳&#xff1c;0.03%、水分含量&#xff1c;0.0067%&#xff09; 一氧化碳对人体有害&#xff0c;过量的二氧化碳也会影响人的呼吸&a…