QT快速操作Excel的实现介绍及操作类封装

news2024/11/25 1:19:49

QT中操作Excel还是比较简单的,Qt提供了QAxObject,包装COM组件的类,通过COM通过COM操作使用QAxObject类,使用此类,需要在pro文件中添加"QT  += axcontainer "。

基本流程介绍

QAxObject:
QAxObject是Qt提供给程序员从代码中访问Office的对象类,其本质上是一个面向微软操作系统的COM接口,它操作Excel的基本流程如下:

在这里插入图片描述

 QAxObject将所有Office的工作簿、表格、文档等都作为其子对象,程序员通过调用querySubObject()这个统一的方法来获取各个子对象的实例,再用dynamicCall()方法执行各对象上的具体操作。QT中Excel的使用,在工程配置上需要QT += axcontainer

具体过程

1.启动Excel进程,获取Excel工作簿集
创建Excel进程使用如下语句:

QAxObject *myexcel = new QAxObject("Excel.Application"); 

其中,myexcel为进行的实例对象名,该名称由用户自己定义,整个程序中引用一致即可。
通过进程获取Excel工作簿集,语句为:

QAxObject *myworks = myexcel->querySubObject("WorkBooks"); 

其中,myworks是工作簿集的引用,用户可根据需要定义其名称,同样,在程序中也要求引用一致。
有了Excel进程和工作簿集的引用,就可以使用它们对Excel进行一系列文档级别的操作。例如:

myworks->dynamicCall("Add");                //添加一个工作簿
myexcel->querySubObject("ActiveWorkBook");       //获取当前活动的工作簿

2.获取电子表格集
每个Excel工作簿中都可以包含若干电子表格(Sheet),通过打开的当前工作簿获取其所有电子表格的程序语句为:

QAxObject *mysheets = workbook->querySubObject("Sheets"); 

其中,workbook也是一个QAxObject对象,引用的是当前正在操作的一个活动工作簿。
同理,在获取了电子表格集后,就可以像操作工作簿文档那样,对其中的表格执行各种操作。例如:

mysheets->dynamicCall("Add");                //添加一个表格
workbook->querySubObject("ActiveSheet")    //获取工作簿中当前活动表格
sheet->setProperty("Name",字符串)            //给表格命名

3.操作单元格及其数据
对Excel的操作最终要落实到对某个电子表格单元格中数据信息的读写上,在Qt中的Excel单元格同样是作为QAxObject对象来看待的,对它的操作通过其所在表格的QAxObject对象句柄执行,如下:

QAxObject *cell = sheet->querySubObject("Range(QVariant, QVariant)", 单元格编号); 
cell->dynamicCall("SetValue(const QVariant&)", QVariant(字符串)); 

这样,就实现了对Excel各个级别对象的灵活操作和使用。
为避免资源无谓消耗和程序死锁,通常在编程结束时还必须通过语句释放该Excel进程所占据的系统资源,如下:

workbook->dynamicCall("Close()"); //关闭工作簿 
myexcel->dynamicCall("Quit()"); //退出进程

两种写入方法举例

方法一,直观,但写入低效。

bool MainWindow::saveToExcel(QString &filepath)
{
    if(!filepath.isEmpty()){
        QAxObject *excel = new QAxObject(this);
        excel->setControl("Excel.Application");//连接Excel控件
        excel->dynamicCall("SetVisible (bool Visible)","false");//不显示窗体
        excel->setProperty("DisplayAlerts", false);//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示

        QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合
        workbooks->dynamicCall("Add");//新建一个工作簿
        //QAxObject *workbook = workbooks->querySubObject("Open(QString&)",filepath);
        QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿
        QAxObject *worksheets = workbook->querySubObject("Sheets");//获取工作表集合
        QAxObject *worksheet = worksheets->querySubObject("Item(int)",1);//获取工作表集合的工作表1,即sheet1

        QAxObject *cellA,*cellB,*cellC,*cellD,*cellE,*cellF;

        //设置标题
        int cellrow=1;
        QString A="A"+QString::number(cellrow);//设置要操作的单元格,如A1
        QString B="B"+QString::number(cellrow);
        QString C="C"+QString::number(cellrow);
        QString D="D"+QString::number(cellrow);
        QString E="E"+QString::number(cellrow);
        QString F="F"+QString::number(cellrow);

        cellA = worksheet->querySubObject("Range(QVariant, QVariant)",A);//获取单元格
        cellB = worksheet->querySubObject("Range(QVariant, QVariant)",B);
        cellC=worksheet->querySubObject("Range(QVariant, QVariant)",C);
        cellD=worksheet->querySubObject("Range(QVariant, QVariant)",D);
        cellE=worksheet->querySubObject("Range(QVariant, QVariant)",E);
        cellF=worksheet->querySubObject("Range(QVariant, QVariant)",F);

        cellA->dynamicCall("SetValue(const QVariant&)",QVariant("通道号"));//设置单元格的值
        cellB->dynamicCall("SetValue(const QVariant&)",QVariant(""));
        cellC->dynamicCall("SetValue(const QVariant&)",QVariant("通道1"));
        cellD->dynamicCall("SetValue(const QVariant&)",QVariant("通道2"));
        cellE->dynamicCall("SetValue(const QVariant&)",QVariant("通道3"));
        cellF->dynamicCall("SetValue(const QVariant&)",QVariant("通道4"));
        cellrow++;
        A="A"+QString::number(cellrow);//设置要操作的单元格,如A2
        B="B"+QString::number(cellrow);
        C="C"+QString::number(cellrow);
        D="D"+QString::number(cellrow);
        E="E"+QString::number(cellrow);
        F="F"+QString::number(cellrow);

        cellA = worksheet->querySubObject("Range(QVariant, QVariant)",A);//获取单元格
        cellB = worksheet->querySubObject("Range(QVariant, QVariant)",B);
        cellC=worksheet->querySubObject("Range(QVariant, QVariant)",C);
        cellD=worksheet->querySubObject("Range(QVariant, QVariant)",D);
        cellE=worksheet->querySubObject("Range(QVariant, QVariant)",E);
        cellF=worksheet->querySubObject("Range(QVariant, QVariant)",F);

        cellA->dynamicCall("SetValue(const QVariant&)",QVariant("量纲类型"));//设置单元格的值
        cellB->dynamicCall("SetValue(const QVariant&)",QVariant(""));
        cellC->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellD->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellE->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellF->dynamicCall("SetValue(const QVariant&)",QVariant("L/M"));

        cellrow++;
        int rows=mTbData.recList.size();
        for(int i=0;i<rows;i++){
            A="A"+QString::number(cellrow);//设置要操作的单元格,如A6
            B="B"+QString::number(cellrow);
            C="C"+QString::number(cellrow);
            D="D"+QString::number(cellrow);
            E="E"+QString::number(cellrow);
            F="F"+QString::number(cellrow);

            cellA = worksheet->querySubObject("Range(QVariant, QVariant)",A);//获取单元格
            cellB = worksheet->querySubObject("Range(QVariant, QVariant)",B);
            cellC=worksheet->querySubObject("Range(QVariant, QVariant)",C);
            cellD=worksheet->querySubObject("Range(QVariant, QVariant)",D);
            cellE=worksheet->querySubObject("Range(QVariant, QVariant)",E);
            cellF=worksheet->querySubObject("Range(QVariant, QVariant)",F);

            cellA->dynamicCall("SetValue(const QVariant&)",QVariant(i+1));
            cellB->dynamicCall("SetValue(const QVariant&)",QVariant(mTbData.recList.at(i).value("collect_date")));
            cellC->dynamicCall("SetValue(const QVariant&)",QVariant(mTbData.recList.at(i).value("shelf_value0")));
            cellD->dynamicCall("SetValue(const QVariant&)",QVariant(mTbData.recList.at(i).value("shelf_value1")));
            cellE->dynamicCall("SetValue(const QVariant&)",QVariant(mTbData.recList.at(i).value("shelf_value2")));
            cellF->dynamicCall("SetValue(const QVariant&)",QVariant(mTbData.recList.at(i).value("X_Liu_Value3")));

            cellrow++;
        }

        //workbook->dynamicCall("Save()");   //!保存文件
        workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(filepath));//保存至filepath,注意一定要用QDir::toNativeSeparators将路径中的"/"转换为"\",不然一定保存不了。
        workbook->dynamicCall("Close()");
        excel->dynamicCall("Quit()");
        if (excel)
        {
            delete excel;
            excel = NULL;
        }
        return true;
        //
    }

    return false;
}

方法二,写入效率高,推荐使用这种。

void MainWindow::on_btn_export_clicked()
{

    QString filepath=QFileDialog::getSaveFileName(this,tr("保存数据"),".",tr("Microsoft Office 2007 (*.xlsx)"));//获取保存路径
    auto ret = saveToExcel_fast(filepath);
    if(ret){
        QMetaObject::invokeMethod(qApp, []{
            QMessageBox::information(0 ,"提示" ,"数据保存成功", QMessageBox::Ok | QMessageBox::Default , 0 );
        });
    }
    /*
    QFuture<void> future = QtConcurrent::run([this,filepath](){
        QString fpath = filepath;
        auto ret = saveToExcel_fast(fpath);
        if(ret){
            QMetaObject::invokeMethod(qApp, []{
                QMessageBox::information(0 ,"提示" ,"数据保存成功", QMessageBox::Ok | QMessageBox::Default , 0 );
            });
        }
    });*/
}
bool MainWindow::saveToExcel_fast(QString &filepath)
{
    if(!filepath.isEmpty()){
        QAxObject *excel = new QAxObject(this);
        excel->setControl("Excel.Application");//连接Excel控件
        excel->dynamicCall("SetVisible (bool Visible)","false");//不显示窗体
        excel->setProperty("DisplayAlerts", false);//不显示任何警告信息。如果为true那么在关闭是会出现类似“文件已修改,是否保存”的提示

        QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合
        workbooks->dynamicCall("Add");//新建一个工作簿
        //QAxObject *workbook = workbooks->querySubObject("Open(QString&)",filepath);
        QAxObject *workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿
        QAxObject *worksheets = workbook->querySubObject("Sheets");//获取工作表集合
        QAxObject *worksheet = worksheets->querySubObject("Item(int)",1);//获取工作表集合的工作表1,即sheet1

        QAxObject *cellA,*cellB,*cellC,*cellD,*cellE,*cellF;

        //设置标题
        int cellrow=1;
        QString A="A"+QString::number(cellrow);//设置要操作的单元格,如A1
        QString B="B"+QString::number(cellrow);
        QString C="C"+QString::number(cellrow);
        QString D="D"+QString::number(cellrow);
        QString E="E"+QString::number(cellrow);
        QString F="F"+QString::number(cellrow);

        cellA = worksheet->querySubObject("Range(QVariant, QVariant)",A);//获取单元格
        cellB = worksheet->querySubObject("Range(QVariant, QVariant)",B);
        cellC=worksheet->querySubObject("Range(QVariant, QVariant)",C);
        cellD=worksheet->querySubObject("Range(QVariant, QVariant)",D);
        cellE=worksheet->querySubObject("Range(QVariant, QVariant)",E);
        cellF=worksheet->querySubObject("Range(QVariant, QVariant)",F);

        cellA->dynamicCall("SetValue(const QVariant&)",QVariant("通道号"));//设置单元格的值
        cellB->dynamicCall("SetValue(const QVariant&)",QVariant(""));
        cellC->dynamicCall("SetValue(const QVariant&)",QVariant("通道1"));
        cellD->dynamicCall("SetValue(const QVariant&)",QVariant("通道2"));
        cellE->dynamicCall("SetValue(const QVariant&)",QVariant("通道3"));
        cellF->dynamicCall("SetValue(const QVariant&)",QVariant("通道4"));
        cellrow++;
        A="A"+QString::number(cellrow);//设置要操作的单元格,如A2
        B="B"+QString::number(cellrow);
        C="C"+QString::number(cellrow);
        D="D"+QString::number(cellrow);
        E="E"+QString::number(cellrow);
        F="F"+QString::number(cellrow);

        cellA = worksheet->querySubObject("Range(QVariant, QVariant)",A);//获取单元格
        cellB = worksheet->querySubObject("Range(QVariant, QVariant)",B);
        cellC=worksheet->querySubObject("Range(QVariant, QVariant)",C);
        cellD=worksheet->querySubObject("Range(QVariant, QVariant)",D);
        cellE=worksheet->querySubObject("Range(QVariant, QVariant)",E);
        cellF=worksheet->querySubObject("Range(QVariant, QVariant)",F);

        cellA->dynamicCall("SetValue(const QVariant&)",QVariant("量纲类型"));//设置单元格的值
        cellB->dynamicCall("SetValue(const QVariant&)",QVariant(""));
        cellC->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellD->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellE->dynamicCall("SetValue(const QVariant&)",QVariant("MPa"));
        cellF->dynamicCall("SetValue(const QVariant&)",QVariant("L/M"));

        cellrow++;

        QList<QVariant> rowdata;

        int rows=mTbData.recList.size();

        for (int i = 0; i < rows;i++) {
            QList<QVariant> aline;

            aline.append(QVariant(i+1));
            aline.append(QVariant(mTbData.recList.at(i).value("collect_date")));
            aline.append(QVariant(mTbData.recList.at(i).value("shelf_value0")));
            aline.append(QVariant(mTbData.recList.at(i).value("shelf_value1")));
            aline.append(QVariant(mTbData.recList.at(i).value("shelf_value2")));
            aline.append(QVariant(mTbData.recList.at(i).value("X_Liu_Value3")));

            QVariant conv(aline);
            rowdata.append(conv);
        }
        QVariant d(rowdata);

        QString nA = "A" + QString::number(cellrow) + ":" + "F" + QString::number(rows+cellrow);

        qDebug() << nA;
        QAxObject *range = worksheet->querySubObject("Range(QString)", nA);

        if(NULL == range || range->isNull())
        {
            return false;
        }
        range->setProperty("Value", d);

        //workbook->dynamicCall("Save()");   //!保存文件
        workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(filepath));//保存至filepath,注意一定要用QDir::toNativeSeparators将路径中的"/"转换为"\",不然一定保存不了。
        workbook->dynamicCall("Close()");
        excel->dynamicCall("Quit()");
        if (excel)
        {
            delete excel;
            excel = NULL;
        }
        return true;
        //
    }

    return false;
}

操作Excel类简单封装

#ifndef MYEXCEL_H
#define MYEXCEL_H

#include <QString>
#include <QVariant>
#include <QColor>
#include <QAxObject>

/*excel操作*/
enum class ColumnType{
    ColumnA = 1,
    ColumnB = 2,
    ColumnC = 3,
    ColumnD = 4,
    ColumnE = 5,
    ColumnF = 6,
    ColumnG = 7,
    ColumnH = 8,
    ColumnI = 9
};

class MyExcel
{
public:
    MyExcel();

    /**
     * @brief writeOneTable 批量写入数据 效率高
     * @param filepath 文件路径
     * @param startRow 起始的列
     * @param table 要保存的表(二维数据)
     * @return
     */
    bool writeOneTable(const QString &filepath, int startRow,QVector<QVector<QVariant>> & table);

    /**
     * @brief saveAs 另存为 对话框
     * @return
     */
    QString saveAs();

    /**
     * @brief setOneCell 设置单行Excel数据,效率低
     * @param worksheet
     * @param column
     * @param row
     * @param color
     * @param text
     */
    void setOneCell(QAxObject *worksheet,ColumnType column,int row,QColor color,QString text);

private:
    void convertToColName(int data, QString& res);
    QString to26AlphabetString(int data);

};

#endif // MYEXCEL_H
#include "myexcel.h"

#include <QStandardPaths>
#include <QFileDialog>
#include <QRegExp>


MyExcel::MyExcel()
{

}

QString MyExcel::saveAs()
{
    QString file;
    QString filter;
   //如果版本低于QT5,则需要将:
   //  QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),
   //改为:QDesktopServices::storageLocation(QDesktopServices::DesktopLocation),
   file = QFileDialog::getSaveFileName (
               NULL,
               "save",
               QStandardPaths::writableLocation(QStandardPaths::DesktopLocation),      //设置路径, .表示当前路径,./表示更目录
               "Excel(*.xlsx)",     //过滤器
               &filter);

   return file.replace("/","\\");
}

void MyExcel::setOneCell(QAxObject *worksheet, ColumnType column, int row, QColor color, QString text)
{
    QAxObject *cell = worksheet->querySubObject("Cells(int,int)", row, column);
    cell->setProperty("Value", text);
    QAxObject *font = cell->querySubObject("Font");
    font->setProperty("Color", color);
}

bool MyExcel::writeOneTable(const QString &filepath, int startRow,QVector<QVector<QVariant>> &table)
{
    if (!table.isEmpty() && !filepath.isEmpty())
    {
        //新建excel表
        QAxObject excel("Excel.Application");
        excel.dynamicCall("SetVisible (bool Visible)", "false");
        excel.setProperty("DisplayAlerts", false);
        QAxObject* workbooks = excel.querySubObject("WorkBooks");
        workbooks->dynamicCall("Add");
        QAxObject* workbook = excel.querySubObject("ActiveWorkBook");
        QAxObject* sheet = workbook->querySubObject("WorkSheets(int)", 1);

        //数据转换
        QVariantList tdata;
        QVariant var;
        int row = table.count();
        int col = table[0].count();

        for (int i = 0; i < row; i++)
        {
            //tdata << table[i].toList(); //这个地方一定要注意!!!这种写法是错误的
            tdata << QVariant(table[i].toList());//ok
        }
        var = tdata; //注意!

        //例如写入单元格范围A1:L2243
        QString crange;
        convertToColName(col, crange);
        crange = QString("A%1:%2%3").arg(startRow).arg(crange).arg(row+startRow);

        //写入数据
        QAxObject* range = sheet->querySubObject("Range(const QString &)", crange);
        QVariant res = range->setProperty("Value", var);
        delete range;

        //退出
        workbook->dynamicCall("SaveAs(const QString&)", filepath);
        workbook->dynamicCall("Close(Boolean)", false);
        excel.dynamicCall("Quit(void)");

        return true;
    }
    return false;
}

1->A 26->Z 27->AA
void MyExcel::convertToColName(int data, QString &res)
{
    Q_ASSERT(data > 0 && data < 65535);
    int tempData = data / 26;
    if (tempData > 0)
    {
        int mode = data % 26;
        convertToColName(mode, res);
        convertToColName(tempData, res);
    }
    else
    {
        res = (to26AlphabetString(data) + res);
    }
}

QString MyExcel::to26AlphabetString(int data)
{
    QChar ch = data + 0x40;//A对应0x41
    return QString(ch);
}

其他资源

Qt Xlsx使用教程、Qt操作Excel、Qt生成Excel图表、跨平台不依赖Office_qtxlsx_超级大洋葱806的博客-CSDN博客

Qt实战案例(4)——利用Qt读取Excel表格_wendy_ya的博客-CSDN博客

QT学习一:利用QT QAxObject读取Excel表格数据的两种方法比较_qt读取表格文件_兄弟李德胜的博客-CSDN博客

QT关于excel文件的简单操作整理_qt excel文件操作_Xavier_TXHXH的博客-CSDN博客 

Qt之excel 操作使用说明_qt操作excel_音视频开发老舅的博客-CSDN博客 

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

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

相关文章

SAP从入门到放弃系列之pMRP

最近学习pMRP&#xff0c;查了很多博客&#xff0c;机翻一篇内容非常详细的文章&#xff0c;感谢大佬&#xff1a; 原文地址&#xff1a; pMRP–Predictive Material and Resource Planning in SAP S/4HANA : Step by Step execution pMRP https://blogs.sap.com/2020/04/14/p…

机器学习【线性回归】

机器学习【线性回归】 回归预测的结果是离散型变量&#xff0c;身高和年龄 损失函数&#xff1a;SSE&#xff08;误差平方和&#xff09;&#xff0c;RSS&#xff08;残差平方和&#xff09;&#xff0c;误差越大越差 最小二乘法&#xff1a;通过最小化真实值和预测值之间的…

大数据:sparkSQL,历史,DataSet,DataFrame,sparkSession

大数据&#xff1a;sparkSQL 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能很多算法学生都得去找开发&#xff0c;测开 测开的话&#xff0c;你就得学数据库&#xff0c;sql&#xff0c;oracle&#xff0c;尤其sql要学…

第十章:创建和管理表

第十章&#xff1a;创建和管理表 10.1&#xff1a;基础知识 一条数据存储的过程 ​ 存储数据是处理数据的第一步。只有正确地把数据存储起来&#xff0c;我们才能进行有效的处理和分析。否则&#xff0c;只能是一团乱麻&#xff0c;无从下手。 ​ 在MySQL中&#xff0c;一个完…

使用模板方法模式封装协议消息

目录 整体框架 模板方法介绍 关于本案例设计 c impl惯用法 cimpl惯用法好处 此案例impl惯用法的设计 关于序列化和反序列化 序列化和反序列化 本项目使用介绍 谷歌测试 谷歌测试环境 谷歌测试用例 完整源码地址 概述 本文介绍了从 设计模式之模板方法模式协议消…

面对CPU狂飙时的5步解决方案

现在企业对后端开发的要求越来越高&#xff0c;不仅要求我们会写代码&#xff0c;还要我们能够进行部署和运维&#xff01; 项目上线并运行一段时间后&#xff0c;可能会发现部署所在的Linux服务器CPU占用过高&#xff0c;该如何排查解决&#xff1f; 本文用5步带你搞定线上CPU…

操作系统-进程和线程-同步、互斥、死锁

目录 一、同步互斥 二、互斥的实现方法 2.1软件实现 2.1.1单标志法 2.1.2双标志先检查 2.1.3双标志后检查 2.1.4Petersons算法 2.2硬件实现 2.2.1 TestAndSet指令 2.2.2 Swap指令 三、信号量机制 3.1整形变量 3.2 记录型变量 3.3用信号量实现进程互斥、同步、前驱关系…

Sui与F1甲骨文红牛车队达成合作

在近期达成的一项为期多年的合作协议中&#xff0c;甲骨文红牛车队将利用Sui网络开发&#xff0c;为粉丝带来全新的数字化体验。 甲骨文红牛车队的粉丝将很快在Sui网络上体验到他们最爱的一级方程式车队带来的激情。最近几个赛季一直统治着F1赛场的甲骨文红牛车队&#xff0c;与…

代码随想录算法训练营第五十三天 | 力扣 1143.最长公共子序列, 1035.不相交的线, 53. 最大子序和

1143.最长公共子序列 题目 1143. 最长公共子序列 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符…

2022年值得关注的7个主要SD-WAN趋势

随着SD-WAN技术在2022年继续发展成熟&#xff0c;该技术在集成远程访问、自动化和多云连接方面的支持有望得到更多的改进。 软件定义WAN仍然是增强用户体验(UX)&#xff0c;提高安全性&#xff0c;以及提供与基于云计算的应用程序的连接的一项关键技术。 随着SD-WAN的成熟&…

java设计模式之:原型模式

在我们的生活中&#xff0c;有很多例子&#xff0c;都是用到了原型模式&#xff0c;例如&#xff1a;我们去配钥匙的时候&#xff0c;肯定先要有一个原配钥匙才可以去配钥匙&#xff1b;《西游记》中孙悟空可以用猴毛根据自己的形象&#xff0c;复制&#xff08;又称“克隆”或…

时间序列预测 | Matlab基于北方苍鹰算法优化随机森林(NGO-RF)与随机森林(RF)的时间序列预测对比

文章目录 效果一览文章概述部分源码参考资料效果一览 文章概述 时间序列预测 | Matlab基于北方苍鹰算法优化随机森林(NGO-RF)与随机森林(RF)的时间序列预测对比 评价指标包括:MAE、RMSE和R2等,代码质量极高,方便学习和替换数据。要求2018版本及以上。 部分源码 %-----------…

【Apache-Flink零基础入门】「入门到精通系列」手把手+零基础带你玩转大数据流式处理引擎Flink(基础概念解析)

手把手零基础带你玩转大数据流式处理引擎Flink 前言介绍Apache Flink 的定义、架构及原理Flink应用服务Streams有限数据流和无限数据流的区别 StateTimeAPI Flink架构体系 Flink操作处理Flink 的应用场景Flink 的应用场景&#xff1a;Data Pipeline实时数仓搜索引擎推荐 Flink …

华为诺亚 VanillaNet

文章标题&#xff1a;《VanillaNet: the Power of Minimalism in Deep Learning》 文章地址&#xff1a;https://arxiv.org/abs/2305.12972 github地址&#xff1a;https://github.com/huawei-noah/VanillaNet 华为诺亚方舟实验室和悉尼大学&#xff0c;2023年5月代码刚开源的…

基于HAL库的STM32的单定时器的多路输入捕获测量脉冲频率(外部时钟实现)

目录 写在前面 一般的做法&#xff08;定时器单通道输入捕获) 以外部时钟的方式(高低频都适用) 测试效果 写在前面 STM32的定时器本身有输入捕获的功能。可选择双端捕获&#xff0c;上升沿捕获或者是下降沿捕获。对应捕获频率来说,连续捕获上升沿或下降沿的时间间隔就是其脉…

手把手教你F103工程文件的创建并且通过protesu仿真验证创建工程文件的正确性(低成本)

目录 一、新建工程文件夹 二、新建一个工程框架 三、添加文件 四、仿真验证 五、仿真调试中遇到的问题并解决 一、新建工程文件夹 新建工程文件夹分为 2 个步骤&#xff1a;1&#xff0c;新建工程文件夹&#xff1b;2&#xff0c;拷贝工程相关文件。 1.新建工程文件 首先…

【04】STM32·HAL库开发-MDK5使用技巧 |文本美化 | 代码编辑技巧 | 查找与替换技巧 | 编译问题定位 | 窗口视图初始化

目录 1.文本美化&#xff08;熟悉&#xff09;1.1编辑器设置1.2字体和颜色设置1.3用户关键字设置1.4代码提示&语法检测1.5global.prop文件妙用 2.代码编辑技巧&#xff08;熟悉&#xff09;2.1Tab键的妙用2.2快速定位函数或变量被定义的地方2.3快速注释&快速取消注释 3…

python面向对象操作2(速通版)

目录 一、私有和公有属性的定义和使用 1.公有属性定义和使用 2.私有属性 二、继承 1.应用 2.子类不能用父类的私有方法 3.子类初始化父类 4.子类重写和调用父类方法 5.多层继承 6.多层继承-初始化过程 7.多继承基本格式 8.多层多继承时的初始化问题 9.多继承初始化…

云原生Docker Cgroups资源控制操作

资源控制 Docker 通过 Cgroup 来控制容器使用的资源配额&#xff0c;包括 CPU、内存、磁盘三大方面&#xff0c; 基本覆盖了常见的资源配额和使用量控制。 Cgroup 是 ControlGroups 的缩写&#xff0c;是 Linux 内核提供的一种可以限制、记录、隔离进程组所使用的物理资源(如…

Node服务器-express框架

1 Express认识初体验 2 Express中间件使用 3 Express请求和响应 4 Express路由的使用 5 Express的错误处理 6 Express的源码解析 一、手动创建express的过程&#xff1a; 1、在项目文件的根目录创建package.json文件 npm init 2、下载express npm install express 3、基本…