Qt——升级系列(Level Seven):事件、文件

目录

Qt事件

  事件介绍

  事件的处理

  按键事件

  鼠标事件

  定时器

  事件分发器

  事件过滤器

Qt文件

  Qt文件概述

  输入输出设备类

  文件读写类

  文件和目录信息类


Qt事件

  事件介绍

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

常⻅的 Qt 事件如下:

常⻅事件描述: 

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

  事件的处理

        事件处理⼀般常⽤的⽅法为:重写相关的 Event 函数。

        在 Qt 中,⼏乎所有的 Event 函数都是虚函数,所以可以重新实现。如:在实现⿏标的进⼊和离开事件时,直接重新实现 enterEvent() 和 leaveEvent() 即可。

enterEvent() 和 leaveEvent() 函数原型如下:

  按键事件

        Qt 中的按键事件是通过 QKeyEvent 类来实现的。当键盘上的按键被按下或者被释放时,键盘事件便会触发。在帮助⽂档中查找 QKeyEvent 类如下:

        查找按键事件中所有的按键类型:在帮助⽂档中输⼊:Qt::Key,如下图:  

        单个按键的例子

1、单个按键的按下事件: 

void MyWidget::keyPressEvent(QKeyEvent *event) 
{
    if (event->key() == Qt::Key_A) 
    {
        qDebug() << "按下了 A 键";
        // 执行相应的操作
    }
    QWidget::keyPressEvent(event);  // 传递事件给父类处理
}

2、单个按键的释放事件: 

void MyWidget::keyReleaseEvent(QKeyEvent *event) 
{
    if (event->key() == Qt::Key_A) 
    {
        qDebug() << "释放了 A 键";
        // 执行相应的操作
    }
    QWidget::keyReleaseEvent(event);  // 传递事件给父类处理
}

        组合按键的例子

1、同时按下多个键的事件:

void MyWidget::keyPressEvent(QKeyEvent *event) 
{
    if (event->modifiers() & Qt::ControlModifier && event->key() == Qt::Key_C) 
    {
        qDebug() << "同时按下了 Ctrl + C 键";
        // 执行相应的操作
    }
    QWidget::keyPressEvent(event);  // 传递事件给父类处理
}

 2、同时释放多个键的事件:

void MyWidget::keyReleaseEvent(QKeyEvent *event) 
{
    if (event->modifiers() & Qt::ShiftModifier && event->key() == Qt::Key_F) 
    {
        qDebug() << "同时释放了 Shift + F 键";
        // 执行相应的操作
    }
    QWidget::keyReleaseEvent(event);  // 传递事件给父类处理
}

在上述示例中:

  • keyPressEvent()keyReleaseEvent() 函数分别处理按键按下和释放事件。
  • 使用 QKeyEvent 对象的 key() 方法获取按下或释放的具体按键。
  • 使用 modifiers() 方法可以获取同时按下的修饰键(如 Ctrl、Shift 等)。
  • 在处理完事件后,通常会调用 QWidget::keyPressEvent(event)QWidget::keyReleaseEvent(event) 将事件传递给父类处理,以确保其他部分的事件处理逻辑能够正常运行。

  鼠标事件

        在 Qt 中,⿏标事件是⽤ QMouseEvent 类来实现的。当在窗⼝中按下⿏标或者移动⿏标时,都会产⽣⿏标事件。

        利⽤ QMouseEvent 类可以获取⿏标的哪个键被按下了以及⿏标的当前位置等信息。在 Qt 帮助⽂档中查找QMouseEvent类 如下图⽰:

        鼠标单击事件的例子

void MyWidget::mousePressEvent(QMouseEvent *event) 
{
    if (event->button() == Qt::LeftButton) 
    {
        qDebug() << "左键被按下";
        // 执行相应的操作
    } 
    else if (event->button() == Qt::RightButton) 
    {
        qDebug() << "右键被按下";
        // 执行相应的操作
    }
    QWidget::mousePressEvent(event);  // 传递事件给父类处理
}

        鼠标释放事件的例子

void MyWidget::mouseReleaseEvent(QMouseEvent *event) 
{
    if (event->button() == Qt::LeftButton) 
    {
        qDebug() << "左键被释放";
        // 执行相应的操作
    } 
    else if (event->button() == Qt::RightButton) 
    {
        qDebug() << "右键被释放";
        // 执行相应的操作
    }
    QWidget::mouseReleaseEvent(event);  // 传递事件给父类处理
}

        鼠标双击事件的例子

void MyWidget::mouseDoubleClickEvent(QMouseEvent *event) 
{
    if (event->button() == Qt::LeftButton) 
    {
        qDebug() << "左键双击";
        // 执行相应的操作
    } 
    else if (event->button() == Qt::RightButton) 
    {
        qDebug() << "右键双击";
        // 执行相应的操作
    }
    QWidget::mouseDoubleClickEvent(event);  // 传递事件给父类处理
}

        鼠标移动事件的例子

void MyWidget::mouseMoveEvent(QMouseEvent *event) 
{
    qDebug() << "鼠标移动到 (" << event->pos().x() << ", " << event->pos().y() << ")";
    // 执行相应的操作,例如更新鼠标位置的显示等
    QWidget::mouseMoveEvent(event);  // 传递事件给父类处理
}

        鼠标滚轮事件的例子 

void MyWidget::wheelEvent(QWheelEvent *event) 
{
    if (event->delta() > 0) 
    {
        qDebug() << "鼠标向上滚动";
        // 执行相应的操作
    } 
    else if (event->delta() < 0) 
    {
        qDebug() << "鼠标向下滚动";
        // 执行相应的操作
    }
    QWidget::wheelEvent(event);  // 传递事件给父类处理
}

  定时器

        Qt 中在进⾏窗⼝程序的处理过程中,经常要周期性的执⾏某些操作,或者制作⼀些动画效果,使⽤定时器就可以实现。所谓定时器就是在间隔⼀定时间后,去执⾏某⼀个任务。定时器在很多场景下都会使⽤到,如弹窗⾃动关闭之类的功能等。

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

QTimerEvent 类

        QTimerEvent类是用来描述定时器事件的类。它通常与 QObjecttimerEvent() 函数结合使用,用于处理定时器事件的回调操作。

使用方法:

  1. 启动定时器: 通过 startTimer() 函数启动一个定时器,该函数接受一个毫秒为单位的时间间隔作为参数,并返回一个整型值,代表该定时器的唯一标识符(定时器编号)。

  2. 定时器事件处理: 当定时器设定的时间间隔到达时,会触发 timerEvent() 函数。在 timerEvent() 函数中,可以通过传入的参数 QTimerEvent *event 来获取定时器的具体信息,例如定时器的标识符,从而执行相应的操作。

  3. 代码示例:

    void MyWidget::timerEvent(QTimerEvent *event) 
    {
        if (event->timerId() == timerId) 
        {
            qDebug() << "定时器事件触发,定时器ID:" << event->timerId();
            // 执行相应的定时操作
        }
        QWidget::timerEvent(event);  // 传递事件给父类处理
    }
    

QTimer 类

        QTimer类提供了更高级别的定时器功能,其主要特点是能够通过信号和槽机制来处理定时器事件,以及提供更多的灵活性和控制选项。

主要功能:

  1. 启动定时器: 通过 QTimerstart() 函数启动定时器,该函数接受一个毫秒为单位的时间间隔作为参数,还可以选择性地设置定时器的单次触发或重复触发。

  2. 定时器信号和槽: QTimer 可以通过信号 timeout() 来定期触发定时器事件。可以通过连接(connect)这个信号到槽函数来处理定时器事件,这使得定时器的使用更加方便和直观。

  3. 单次运行定时器: 可以使用 setSingleShot(true) 方法设置定时器为只运行一次,适用于需要在一段时间后执行一次任务的场景。

  4. 代码示例:

    // 创建一个 QTimer 对象
    QTimer *timer = new QTimer(this);
    
    // 设置定时器触发的时间间隔,单位为毫秒
    timer->setInterval(1000); // 1秒
    
    // 连接定时器的 timeout() 信号到槽函数
    connect(timer, &QTimer::timeout, [=]() 
    {
        qDebug() << "定时器触发";
        // 执行相应的定时操作
    });
    
    // 启动定时器
    timer->start();
    

区别和选择:

  • QTimerEvent 和 timerEvent(): 适合在自定义的 QObject 派生类中处理定时器事件,需要手动管理定时器的标识符和事件处理逻辑。

  • QTimer 类: 更高级别的接口,通过信号和槽机制处理定时器事件,适合在需要简单设置和操作定时器的场景下使用,无需手动管理定时器事件。

  事件分发器

        概述

        在 Qt 中,事件分发器(Event Dispatcher) 是⼀个核⼼概念,⽤于处理 GUI 应⽤程序中的事件。事件分发器负责将事件从⼀个对象传递到另⼀个对象,直到事件被处理或被取消。每个继承⾃ QObject类 或 QObject类 本⾝都可以在本类中重写 bool event(QEvent *e) 函数,来实现相关事件的捕获和拦截。

        事件分发器⼯作原理

        在 Qt 中,我们发送的事件都是传给了 QObject 对象,更具体点是传给了 QObject 对象的 event() 函数。所有的事件都会进⼊到这个函数⾥⾯,那么我们处理事件就要重写这个 event() 函数。event() 函数本⾝不会去处理事件,⽽是根据 事件类型(type值)调⽤不同的事件处理函数。事件分发器就是⼯作在应⽤程序向下分发事件的过程中,如下图:

        如上图,事件分发器⽤于分发事件。在此过程中,事件分发器也可以做拦截操作。事件分发器主要是通过 bool event(QEvent *e) 函数来实现。其返回值为布尔类型,若为 ture,代表拦截,不向下分发。

        Qt 中的事件是封装在 QEvent类 中,在 Qt 助⼿中输⼊ QEvent 可以查看其所包括的事件类型,如下图示:

        在Qt中声明和实现鼠标点击事件、事件分发器以及拦截事件时,通常会遵循以下步骤。下面是一个基本的示例,分别在头文件 widget.h 和实现文件 widget.cpp 中展示如何完成这些操作。

widget.h 头文件中声明

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QMouseEvent>

class Widget : public QWidget
{
    Q_OBJECT

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

protected:
    // 声明鼠标点击事件处理函数
    void mousePressEvent(QMouseEvent *event) override;

    // 声明事件分发器函数
    bool event(QEvent *event) override;

private:
    // 声明拦截事件处理函数
    bool eventFilter(QObject *watched, QEvent *event) override;
};

#endif // WIDGET_H

widget.cpp 实现文件中实现

#include "widget.h"
#include <QDebug>

Widget::Widget(QWidget *parent) : QWidget(parent)
{
    // 安装事件过滤器,用于拦截事件
    this->installEventFilter(this);
}

Widget::~Widget()
{
}

// 实现鼠标点击事件处理函数
void Widget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) 
    {
        qDebug() << "左键点击,位置:" << event->pos();
        // 执行相应的操作
    } 
    else if (event->button() == Qt::RightButton) 
    {
        qDebug() << "右键点击,位置:" << event->pos();
        // 执行相应的操作
    }

    // 将事件传递给父类处理
    QWidget::mousePressEvent(event);
}

// 实现事件分发器函数
bool Widget::event(QEvent *event)
{
    if (event->type() == QEvent::MouseButtonPress) 
    {
        // 处理鼠标按下事件
        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
        qDebug() << "事件分发器捕获到鼠标按下事件,位置:" << mouseEvent->pos();
        // 执行相应的操作
        return true; // 表示事件已处理
    }

    // 其他事件交给父类处理
    return QWidget::event(event);
}

// 实现事件过滤器函数
bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if (watched == this && event->type() == QEvent::MouseMove) 
    {
        // 拦截并处理鼠标移动事件
        QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
        qDebug() << "事件过滤器捕获到鼠标移动事件,位置:" << mouseEvent->pos();
        // 执行相应的操作
        return true; // 表示事件已处理
    }

    // 其他事件交给父类处理
    return QWidget::eventFilter(watched, event);
}

 代码说明:

  • mousePressEvent 函数: 在该函数中处理鼠标点击事件。根据 QMouseEventbutton() 方法判断是左键还是右键,并可以获取鼠标点击的位置信息。

  • event 函数: 这是事件分发器函数,用于捕获所有类型的事件。在示例中,通过判断事件的类型 (QEvent::MouseButtonPress) 来处理鼠标按下事件。

  • eventFilter 函数: 这是事件过滤器函数,通过调用 installEventFilter() 函数安装到对象上。在示例中,通过判断事件类型 (QEvent::MouseMove) 来处理鼠标移动事件。

  事件过滤器

        在 Qt 中,⼀个对象可能经常要查看或拦截另外⼀个对象的事件,如对话框想要拦截按键事件,不让别的组件接收到,或者修改按键的默认值等。通过上⾯的学习,我们已经知道,Qt 创建了 QEvent事件对象之后,会调⽤QObject 的 event()函数 处理事件的分发。显然,我们可以在 event()函数 中实现拦截的操作。由于 event()函数是 protected 的,因此,需要继承已有类。如果组件很多,就需要重写很多个event()函数。这当然相当⿇烦,更不⽤说重写 event()函数还得⼩⼼⼀堆问题。好在 Qt 提供了另外⼀种机制来达到这⼀⽬的:事件过滤器。

        事件过滤器是在应⽤程序分发到 event事件分发器 之前,再做⼀次更⾼级的拦截。如下图⽰:

事件过滤器的⼀般使⽤步骤:
    1、安装事件过滤器;
    2、重写事件过滤器函数:eventfilter() 。 

        假设我们有一个 MyWidget 类,它继承自 QWidget,并希望在该小部件上安装事件过滤器来拦截按键事件。以下是如何在 widget.cpp 中实现这个示例:

#include "widget.h"
#include <QDebug>
#include <QKeyEvent>

Widget::Widget(QWidget *parent) : QWidget(parent)
{
    // 创建一个 QLabel 作为被监视对象
    QLabel *label = new QLabel("监视对象", this);
    label->setGeometry(50, 50, 100, 30); // 设置标签的位置和大小

    // 安装事件过滤器到 label 上
    label->installEventFilter(this);
}

bool Widget::eventFilter(QObject *watched, QEvent *event)
{
    if (watched->objectName() == "监视对象") 
    {
        if (event->type() == QEvent::KeyPress) 
        {
            QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
            qDebug() << "按键事件被拦截:按键" << keyEvent->key() << "被按下";
            
            // 在此处可以根据需求修改事件或者阻止事件继续传递
            // 例如,拦截所有按键事件,不让它传递给监视对象
            return true; // 返回 true 表示事件已处理
        }
    }

    // 其他事件交给父类处理
    return QWidget::eventFilter(watched, event);
}

示例说明:

  1. 安装事件过滤器:Widget 类的构造函数中,我们创建了一个 QLabel 对象作为被监视对象,并通过 installEventFilter() 函数将当前小部件 (this) 设置为其事件过滤器。

  2. 重写事件过滤器函数:eventFilter() 函数中,我们对事件进行检查和处理。在示例中,我们检查了被监视对象的对象名是否为 "监视对象",如果是,并且事件类型为 QEvent::KeyPress,则我们拦截并处理按键事件。在实际应用中,你可以根据需要修改事件内容、记录日志、阻止事件继续传递等操作。

  3. 返回值解释: 如果事件被处理了并且不需要传递给被监视对象,则返回 true;否则,返回 QWidget::eventFilter(watched, event),以继续将事件传递给父类处理。

Qt文件

  Qt文件概述

        ⽂件操作是应⽤程序必不可少的部分。Qt 作为⼀个通⽤开发库,提供了跨平台的⽂件操作能⼒。 Qt提供了很多关于⽂件的类,通过这些类能够对⽂件系统进⾏操作,如⽂件读写、⽂件信息获取、⽂件复制或重命名等。

  输入输出设备类

        在 Qt 中,⽂件读写的类为 QFile 。QFile 的⽗类为 QFileDevice ,QFileDevice 提供了⽂件交互操作的底层功能。 QFileDevice 的⽗类是 QIODevice,QIODevice 的⽗类为 QObject 。

        QIODevice 是 Qt 中所有输⼊输出设备(input/output device,简称 I/O 设备)的基础类,I/O 设备就是能进⾏数据输⼊和输出的设备,例如⽂件是⼀种 I/O 设备,⽹络通信中的 socket 是 I/O 设备, 串⼝、蓝⽛等通信接⼝也是 I/O 设备,所以它们也是从 QIODevice 继承来的。Qt 中主要的⼀些 I/O 设备类的继承关系如下图所⽰:

上图中各类的说明如下:
        • QFile 是⽤于⽂件操作和⽂件数据读写的类,使⽤ QFile 可以读写任意格式的⽂件。
        • QSaveFile 是⽤于安全保存⽂件的类。使⽤ QSaveFile 保存⽂件时,它会先把数据写⼊⼀个临时⽂件,成功提交后才将数据写⼊最终的⽂件。如果保存过程中出现错误,临时⽂件⾥的数据不会被写⼊最终⽂件,这样就能确保最终⽂件中不会丢失数据或被写⼊部分数据。 在保存⽐较⼤的⽂件或复杂格式的⽂件时可以使⽤这个类,例如从⽹络上下载⽂件等。
        • QTemporaryFile 是⽤于创建临时⽂件的类。使⽤函数 QTemporaryFile::open() 就能创建⼀个⽂件名唯⼀的临时⽂件,在 QTemporaryFile 对象被删除时,临时⽂件被⾃动删除。
        • QTcpSocket 和 QUdpSocket 是分别实现了 TCP 和 UDP 的类。
        • QSerialPort 是实现了串⼝通信的类,通过这个类可以实现计算机与串⼝设备的通信。
        • QBluetoothSocket 是⽤于蓝⽛通信的类。⼿机和平板计算机等移动设备有蓝⽛通信模块,笔记本电脑⼀般也有蓝⽛通信模块。通过QBluetoothSocket类,就可以编写蓝⽛通信程。如编程实现笔记本电脑与⼿机的蓝⽛通信。
        • QProcess 类⽤于启动外部程序,并且可以给程序传递参数。
        • QBuffer 以⼀个 QByteArray 对象作为数据缓冲区,将 QByteArray 对象当作⼀个 I/O 设备来读写。

  文件读写类

        在 Qt 中,⽂件的读写主要是通过 QFile 类来实现。在 QFile 类中提供了⼀些⽤来读写⽂件的⽅法。对于⽂件的操作主要有:
        • 读数据:QFile 类中提供了多个⽅法⽤于读取⽂件内容;如 read()、readAll()、readLine()等。
        • 写数据:QFile 类中提供了多个⽅法⽤于往⽂件中写内容;如 write()、writeData()等。
        • 关闭⽂件:⽂件使⽤结束后必须⽤函数 close() 关闭⽂件。

        访问⼀个设备之前,需要使⽤ open()函数 打开该设备,⽽且必须指定正确的打开模式,QIODevice 中所有的打开模式由 QIODevice::OpenMode 枚举变量定义,其取值如下:

QIODevice::NotOpen
没有打开设备
QIODevice::ReadOnly
以只读⽅式打开设备
QIODevice::WriteOnly
以只写⽅式打开设备
QIODevice::ReadWrite
以读写⽅式打开设备
QIODevice::Append
以追加⽅式打开设备,数据将写到⽂件末尾
QIODevice::Truncate
每次打开⽂件后重写⽂件内容,原内容将被删除
QIODevice::Text
在读⽂件时,⾏尾终⽌符会被转换为 '\n';当写⼊⽂件时,⾏尾终⽌符会被转换为 本地编码。如 Win32上为'\r\n';
QIODevice::Unbuffered
⽆缓冲形式打开⽂件,绕过设备中的任何缓冲区
QIODevice::NewOnly
⽂件存在则打开失败,不存在则创建⽂件

  文件和目录信息类

        QFileInfo 是 Qt 提供的⼀个⽤于获取⽂件和⽬录信息的类,如获取⽂件名、⽂件⼤⼩、⽂件修改⽇期等。QFileInfo类中提供了很多的⽅法,常⽤的有:
        • isDir() 检查该⽂件是否是⽬录;
        • isExecutable() 检查该⽂件是否是可执⾏⽂件;
        • fileName() 获得⽂件名;
        • completeBaseName() 获取完整的⽂件名;
        • suffix() 获取⽂件后缀名;
        • completeSuffix() 获取完整的⽂件后缀;
        • size() 获取⽂件⼤⼩;
        • isFile() 判断是否为⽂件;
        • fileTime() 获取⽂件创建时间、修改时间、最近访问时间等;

代码示例:

#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 创建一个 QFileInfo 对象,传入文件路径或者文件名
    QFileInfo fileInfo("/path/to/your/file.txt");

    // 获取文件名
    QString fileName = fileInfo.fileName();
    qDebug() << "文件名:" << fileName;

    // 获取文件路径
    QString filePath = fileInfo.filePath();
    qDebug() << "文件路径:" << filePath;

    // 获取文件大小(字节)
    qint64 fileSize = fileInfo.size(); // 返回 qint64 类型
    qDebug() << "文件大小:" << fileSize << "bytes";

    // 获取文件修改日期和时间
    QDateTime lastModified = fileInfo.lastModified();
    qDebug() << "最后修改时间:" << lastModified.toString(Qt::ISODate);

    // 获取文件后缀名
    QString suffix = fileInfo.suffix();
    qDebug() << "文件后缀名:" << suffix;

    // 检查文件是否存在
    if (fileInfo.exists()) 
    {
        qDebug() << "文件存在";
    } 
    else 
    {
        qDebug() << "文件不存在";
    }

    return a.exec();
}

 示例说明:

  1. 包含头文件: 引入了 QFileInfo 类的头文件 <QFileInfo>,以及用于调试输出的 <QDebug>

  2. 创建 QFileInfo 对象: 使用文件路径或文件名创建一个 QFileInfo 对象,例如 "/path/to/your/file.txt"

  3. 获取文件信息:

    • 使用 fileName() 获取文件名。
    • 使用 filePath() 获取文件路径。
    • 使用 size() 获取文件大小,返回 qint64 类型表示文件大小的字节数。
    • 使用 lastModified() 获取文件最后修改时间,返回 QDateTime 对象。
    • 使用 suffix() 获取文件后缀名。
  4. 检查文件存在性: 使用 exists() 函数检查文件是否存在,并根据结果输出相应信息。

  5. 输出信息: 使用 qDebug() 输出获取到的文件信息。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32 ADC精度提升方法

STM32 ADC精度提升方法 Fang XS.1452512966qq.com如果有错误&#xff0c;希望被指出&#xff0c;学习技术的路难免会磕磕绊绊量的积累引起质的变化 硬件方法 优化布局布线&#xff0c;尽量减小其他干扰增加电源、Vref去耦电容使用低通滤波器&#xff0c;或加磁珠使用DCDC时尽…

在Android运行时切换Retrofit Base URL:简化开发环境与生产环境的切换

在运行时切换Retrofit Base URL:简化开发环境与生产环境的切换 在Android开发中,Retrofit是一个由Square开发的类型安全的HTTP客户端库。它为API认证和网络请求提供了一个强大的框架。然而,在开发过程中,我们常常需要在不同的环境(如开发环境和生产环境)之间切换Base UR…

2024上半年剧集市场复盘:质增量减之下,腾讯持续领跑

随着2024上半年结束&#xff0c;剧集市场长视频平台的比拼也告一段落了。 总结2024H1阶段的剧集市场&#xff0c;依旧延续了“高质量增长”的发展路线&#xff0c;具体表现在数量上的减少和质量上的提升&#xff0c;“质增量减”成为这一阶段的关键词。 根据灯塔专业版数据&a…

openCV3.0 C++ 学习笔记补充(自用 代码+注释)---持续更新 二(51-)

环境&#xff1a;OpenCV3.2.0 VS2015 51、Mean-Shift算法分割图像 cv::pyrMeanShiftFiltering() 参考链接&#xff1a;【从零学习OpenCV 4】分割图像——Mean-Shift分割算法 Mean-Shift算法又被称为均值漂移法&#xff0c;是一种基于颜色空间分布(彩色图像的像素值)的图像分割…

java框架的落地实践案例:大数据平台设计与实现

使用 java 框架设计和实现大数据平台可为企业提供数据处理和分析解决方案&#xff0c;使之能够做出数据驱动的决策。系统采用微服务架构&#xff0c;分解数据处理任务为松散耦合组件&#xff0c;构建于 spring boot 等 java 框架之上。数据采集通过kafka 进行&#xff0c;数据清…

【原理】随机森林模型是怎么训练的

本文来自《老饼讲解-BP神经网络》https://www.bbbdata.com/ 目录 一、随机森林简介二、随机森林训练原理2.1. 随机森林的训练流程2.2. 随机森林训练的核心代码 用过随机森林的朋友都知道&#xff0c;随机森林是集成决策的一个经典代表&#xff0c;它通过训练多棵决策树&#xf…

1、线性回归模型

1、主要解决问题类型 1.1 预测分析(Prediction) 线性回归可以用来预测一个变量(通常称为因变量或响应变量)的值,基于一个或多个输入变量(自变量或预测变量)。例如,根据房屋的面积、位置等因素预测房价。 1.2 异常检测(Outlier Detection) 线性回归可以帮助识别数…

鸿蒙应用开发-时间屏幕

点击下载源码&#xff1a; https://download.csdn.net/download/liuhaikang/89509449 做一个时间屏幕&#xff0c;可以点击切换白色和黑色&#xff0c;有渐变效果&#xff0c;使用到了鸿蒙的动画效果。 在这个设计中&#xff0c;我们首先引入了通用能力包&#xff0c;以实现功…

将一个立方体对象的值赋给另一个立方体对象

如果对一个类定义了两个或多个对象&#xff0c;则这些同类的对象之间可以互相赋值&#xff0c;或者说&#xff0c;一个对象的值可以赋给另一个同类的对象。这里所指的对象的值是指对象中所有数据成员的值。 对象之间的赋值也是通过赋值运算符""进行的。本来&…

MYSQL substring_index

1.substring_index( 参数1,参数2 ,参数3 ) 2.group by 也可以用我们起的别名来划分&#xff0c;以及起别名可以不用as SELECT IF(profile LIKE %female,female,male) gender,COUNT(*) number FROM user_submitGROUP BY gender; 3.切割、截取、删除、替换 select -- 替换法 r…

logback log.info耗时异常,RollingFileAppender+TimeBasedRollingPolicy配置踩坑

我喜欢把核心内容放开头 此次log.info耗时异常升高&#xff0c;是由于日志量过大&#xff08;5G甚至以上&#xff09;&#xff0c;并且使用同步阻塞的RollingFileAppenderTimeBasedRollingPolicy&#xff0c;导致log.info一直等待日志文件滚动&#xff0c;造成了异常。解决方式…

innovus:timing报告的精度如何设置

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 innovus设置timing报告精度常用方法: set_global report_precision 6 report_timing&#xff0c;report_net&#xff0c;report_cell_instance_timing&#xff0c;report_cloc…

记录前端发现问题之 mock接口无返回数据导致所有后续接口调用报错:网络异常

1. 背景 就更新了代码&#xff0c;发现新涉及的页面&#xff0c;切换tab 之后会报错网络异常&#xff0c;再次切换其他没涉及的功能页面&#xff0c;继续报错网络异常 测试环境&#xff1a;纯前端代码&#xff0c;后端是前端mock的数据&#xff0c;仅供demo 2. 问题报错 手动…

如何构建智能聊天系统

聊天分为听、思考、读&#xff0c;简单的通过ASR、LLM、TTS三类模型的组合可以实现&#xff0c;最近openai推出支持多模态的GPT-4o模型&#xff0c;可以把三个模型真正融合成在一起。 现在市面上的模型百花齐放&#xff0c;各有所长。要实现可落地的方案&#xff0c;需要结合业…

ffmpeg在powershell和ubuntu终端下的不同格式

在win10下的powershell中&#xff0c;如果想运行一个exe文件&#xff0c;就不能再像cmd命令行一样用名字来直接运行了&#xff0c;否则会提示格式不对。 正确的做法是&#xff1a; . \ffmpeg.exe -re -i video-test.mpr -rtsp_transport tcp -vcodec h264 -f rtsp rtsp://您的…

模拟算法系列|替换所有的问号|提莫攻击|种花问题|Z字形变换|兼具大小写的英文字母|删除字符使频率相同

大家好,我是LvZi,今天带来模拟算法系列|替换所有的问号|提莫攻击|种花问题|Z字形变换|兼具大小写的英文字母|删除字符使频率相同 一.基本概念 模拟算法就是根据题意 模拟出代码的过程,模拟算法的题意往往都很简单,考验的是将思路转化为代码的能力,十分的锻炼代码能力,且能很好…

Zigbee智能家居数据中心:微信小程序实时掌控家居传感器信息

摘要&#xff1a; 本文将介绍如何构建一个基于Zigbee和微信小程序的智能家居网关&#xff0c;实现对家居传感器数据的采集、汇总和展示。用户可通过微信小程序实时查看家中温湿度、光照等环境数据&#xff0c;为智能家居系统提供数据支撑。 关键词&#xff1a; Zigbee&#xf…

信创测试与性能测试的差别是什么?

信创测试和性能测试在多个方面存在显著的区别。 首先&#xff0c;信创测试是一个更为全面和系统的测试过程&#xff0c;它主要针对信创工程项目中的产品、系统等进行测试和验证&#xff0c;以确保其自主可控和满足性能要求。这包括适配测试、功能测试、性能测试、安全测试、兼…

Spring Boot集成geode快速入门Demo

1.什么是geode&#xff1f; Apache Geode 是一个数据管理平台&#xff0c;可在广泛分布的云架构中提供对数据密集型应用程序的实时、一致的访问。Geode 跨多个进程汇集内存、CPU、网络资源和可选的本地磁盘&#xff0c;以管理应用程序对象和行为。它使用动态复制和数据分区技术…

【postgresql】索引

见的索引类型&#xff1a; B-tree 索引&#xff1a;这是最常用的索引类型&#xff0c;适用于大多数查询。B-tree索引可以高效地处理范围查询。 Hash 索引&#xff1a;适用于等值查询&#xff0c;但不支持范围查询。 GiST 索引&#xff1a;通用搜索树&#xff08;GiST&#xf…