• QT读取Excel表格内容到Table Widget


    QT读取Excel表格内容到Table Widget

    前言

    有一个需求是要把Excel的数据导入到QT的Table Widget表格中。我是一个QT新手,在网上找了很多方法,在这里汇总记录一下。

    导读

    目前总共有四种方法:

    一、ODBC 导入
    二、QAxObject 导入
    三、QXlsx 导入
    四、复制导入

    其中方法一至三适用于不加密的Excel文件,如果公司的Excel文件是加密过的,这三个方法是处理不了的,在我使用时是这样,如果有大佬懂的话请多指教。复制导入加密的Excel也能处理的,除非连复制黏贴都加密了,那真是离谱。

    一、ODBC 导入

    首先需要确认是否存在处理Excel的DSN
    我们可以在C:\Windows\SysWOW64文件夹中找到odbcad32.exe,打开
    如果有下面这个就可以了,没有的话看看添加里面有没有,还是没有就再找其他文章安装对应的东西吧,这里就不扩展了
    在这里插入图片描述
    然后就直接写代码就好了,先随便建个QT项目,随便搞个界面
    在这里插入图片描述

    在.pro文件中加入sql
    在这里插入图片描述
    头文件中加入这些

    #include <QStandardPaths>
    #include <QFileDialog>
    #include <QSqlDatabase>
    #include <QSqlQuery>
    #include <QSqlRecord>
    #include <QSqlError>
    #include <QMessageBox>
    #include <QDebug>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    随便在界面中加个按钮,然后创建一个**clicked()**的槽函数
    函数代码如下:

    void MainWindow::on_pushButton_clicked()
    {
        //桌面打开//Qt4
        //QString desktopDir=QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
        //Qt 5
        QString desktopDir=QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
        //选择Excel文件,并获取路径
        QString filePath=QFileDialog::getOpenFileName(NULL,"选择Excel",desktopDir,"*.xlsx *.xls");
        if(filePath.isNull()){
            QMessageBox::warning(NULL, "错误提示", "无法打开excel文件");
            return;
        }
        
        //读取excel
        QSqlDatabase db = QSqlDatabase::addDatabase("QODBC","excel");
        if(!db.isValid())
        {
            QMessageBox::warning(NULL, "错误提示", "数据库驱动异常");
            db.close();
            return;
        }
    
        QString dsn = QString("Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};Readonly=TRUE;DBQ=%1;").arg(filePath);
        db.setDatabaseName(dsn);
        if(!db.open())
        {
            QMessageBox::warning(NULL, "错误提示", "无法打开数据库");
            db.close();
            return;
        }
        QSqlQuery query(db);
        QString tableName = "Sheet1$"; //sheet名,$是必须的
        QString sql="select * from ["+tableName+"]";
        query.exec(sql);
    
        int row = 1; //行号
        while (query.next()) {
            //每次query就是一行数据
            for (int i = 0; i < ui->tableWidget->columnCount() - 1; i++)
            {
                QTableWidgetItem *item = new QTableWidgetItem(QString::number(query.value(i).toDouble(), 'f', 2));
                ui->tableWidget->setItem(row, i + 1, item);
            }
            row++;
        }
        query.clear();
        db.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    使用ODBC时,Excel中的数据格式:
    在这里插入图片描述
    第一行是字段名,格式比较固定

    二、QAxObject 导入

    这个需要在.pro文件中加入axcontainer
    在这里插入图片描述
    头文件中需要加入

    #include <QStandardPaths>
    #include <QFileDialog>
    #include <QMessageBox>
    #include <QDebug>
    #include <QAxObject>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    代码:

    void MainWindow::on_pushButton_2_clicked()
    {
        QString desktopDir=QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
        QString path=QFileDialog::getOpenFileName(NULL,"选择Excel",desktopDir,"*.xlsx *.xls");
        QAxObject *excel = NULL;
        QAxObject *workbooks = NULL;
        QAxObject *workbook = NULL;
        excel = new QAxObject(this);
        if (!excel->setControl("Excel.Application"))
        {
            excel->setControl("ket.Application");
        }
        if (!excel)
        {
            QMessageBox::critical(NULL, "错误信息", "EXCEL对象丢失");
            return;
        }
        excel->dynamicCall("SetVisible(bool)", false);
        workbooks = excel->querySubObject("WorkBooks");
        workbook = workbooks->querySubObject("Open(const QString&)",path);
        QAxObject * worksheet = workbook->querySubObject("WorkSheets(int)", 1); // 获取第一个工作sheet
        QAxObject * usedrange = worksheet->querySubObject("UsedRange");//获取该sheet的使用范围对象
        QAxObject * rows = usedrange->querySubObject("Rows");
        QAxObject * columns = usedrange->querySubObject("Columns");
    
        /*获取行数和列数*/
        int intCols = columns->property("Count").toInt();
        int intRows = rows->property("Count").toInt();
        int intRowStart = usedrange->property("Row").toInt();
        int intColStart = usedrange->property("Column").toInt();
    
        /*获取excel内容*/
        for (int i = intRowStart; i < intRowStart + intRows; i++)  //行
        {
            for (int j = intColStart; j < intColStart + intCols; j++)
            {
                QAxObject *cell = worksheet->querySubObject("Cells(int,int)", i, j);
                QTableWidgetItem *item = new QTableWidgetItem(QString::number(cell->dynamicCall("Value2()").toDouble(), 'f', 2));
                ui->tableWidget->setItem(i, j, item);
                delete cell;
            }
        }
        // 关闭excel
        workbook->dynamicCall("Close(Boolean)",true);
        excel->dynamicCall("Quit(void)");
        delete excel;
        excel = NULL;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    wps使用的是ket.Application
    使用这个时Excel表格的数据格式是这样的:
    在这里插入图片描述
    不需要第一行那个字段名了,直接全是数据就行,但是这种方法处理的速度很慢,可以说是四种方法中最慢的了

    三、QXlsx导入

    这是QT官方推荐的一个开源项目,看github上好像是一个韩国人开发的
    项目的github地址:https://github.com/QtExcel/QXlsx
    当然他也有告诉我们安装的步骤:https://github.com/QtExcel/QXlsx/blob/master/HowToSetProject.md
    那我就大致翻译一下吧
    首先我们先把项目克隆到本地
    在一个新建的文件夹中打开cmd
    在这里插入图片描述
    然后在字符界面中输入下面的命令,回车

    git clone https://github.com/j2doll/QXlsx.git
    
    • 1

    在这里插入图片描述
    下载完成就是一个QXlsx的文件夹
    在这里插入图片描述
    然后打开这个文件夹,里面还有一个QXlsx,把里面的
    在这里插入图片描述
    复制到自己项目的主目录下面
    在这里插入图片描述
    在自己项目的.pro文件中添加

    # QXlsx code for Application Qt project
    QXLSX_PARENTPATH=./         # current QXlsx path is . (. means curret directory)
    QXLSX_HEADERPATH=./header/  # current QXlsx header path is ./header/
    QXLSX_SOURCEPATH=./source/  # current QXlsx source path is ./source/
    include(./QXlsx.pri)
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述
    然后头文件添加

    #include "xlsxdocument.h"
    #include "xlsxchartsheet.h"
    #include "xlsxcellrange.h"
    #include "xlsxchart.h"
    #include "xlsxrichstring.h"
    #include "xlsxworkbook.h"
    using namespace QXlsx;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    完整代码:

    void MainWindow::on_pushButton_3_clicked()
    {
        QString desktopDir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
        QString filepath = QFileDialog::getOpenFileName(NULL,"选择Excel",desktopDir,"*.xlsx *.xls");
        Document xlsxR(filepath);
        if (xlsxR.load()) //加载Excel文件
        {
            for (int row = 1; row <= 4; row++)
            {
                for (int col = 1; col <= 4; col++)
                {
                    Cell* cell = xlsxR.cellAt(row, col); //获取具体位置单元格
                    if (cell != NULL)
                    {
                        QVariant var = cell->readValue(); // 读取单元格的内容
                        QTableWidgetItem *item = new QTableWidgetItem(QString::number(var.toDouble(), 'f', 2));
                        ui->tableWidget->setItem(row, col, item);
                    }
                    else
                    {
                        QMessageBox::warning(NULL, "错误提示", "Excel表格数据格式错误");
                        return;
                    }
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    注意:它的第一个数据的下标是从1开始的
    这种方法的代码量比前面的少,看起来很简洁,速度也快

    四、复制导入

    我用上面的三种方法都发现无法处理公司的加密Excel。虽然可以先解密再导入,但是解密要申请太麻烦了,所以我就想到这种逆天的做法:直接手动复制Excel中想要导入的内容,然后处理系统剪切板中复制到的内容形成一个数组,再依次绘制在表格中,这样就不用管加不加密了。不过面对连复制黏贴都加密的,也是没用的。而且逼格看起来就没用前面那些看起来高级,显得有点low,哈哈哈
    需要导入的头文件:

    //获取剪切板内容
    #include <QClipboard>
    #include <QApplication>
    #include <QMimeData>
    #include <QMessageBox>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    代码:

    void MainWindow::on_pushButton_4_clicked()
    {
        //获取剪切板内容
        QClipboard *clipboard = QApplication::clipboard();
        QString copyContent = clipboard->text();
    
        QStringList splitList = copyContent.split(" \n");
        QStringList dataList;
        for (int i = 0; i < splitList.size() - 1; i++)
        {
            dataList.append(splitList.at(i).split(" \t"));
        }
        if (dataList.size() != 4 * 4)
        {
            QMessageBox::warning(NULL, "错误提示", "请复制正确的表格内容");
            return;
        }
        for (int i = 0; i < dataList.size(); i++)
        {
            qDebug()<<dataList.at(i);
        }
    
        for (int i = 0; i < ui->tableWidget->rowCount() - 1; i++)
        {
            for (int j = 0; j < ui->tableWidget->columnCount() - 1; j++)
            {
                QTableWidgetItem *item = new QTableWidgetItem(dataList.at(i * 4 + j));
                ui->tableWidget->setItem(i + 1, j + 1, item);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    剪切板中的内容是这样的:

    "2.00 \t5.00 \t10.00 \t9.00 \n10.00 \t0.00 \t0.00 \t11.00 \n0.00 \t0.00 \t0.00 \t12.00 \n6.00 \t7.00 \t8.00 \t88.00 \n"
    
    • 1

    所以就先用 \n 来分割成每一行,再用 \t 分割成每个单元格存入数组列表中,注意前面还有个空格
    由于是复制的,所以数据在哪个位置都没问题
    在这里插入图片描述
    我这个操作是先手动复制数据,然后点击界面的按钮进行处理
    在这里插入图片描述

    结尾

    ok,就这么多了,不知道大伙儿还有什么其他方法吗?如果对我这篇文章有不解和建议的话,可以直接评论或者私信我哦。

    附件

    这个演示的项目下载地址(免费的免费的)
    https://download.csdn.net/download/qq_16186465/85847594
    QXlsx资源下载地址(这是我自己上传的,也可以去github正版官网下)
    https://download.csdn.net/download/qq_16186465/85847616

  • 相关阅读:
    go中网络流量分析gopacket库的使用
    为互连智能合约Connected Contracts使用Axelar SDK
    Dubbo Admin修改注册中心为Nacos 以及Nacos整合Dubbo
    【PyTorch 攻略 (3/7)】线性组件、激活函数
    Ubuntu快速安装MSF命令
    Docker 维护
    随时随地查看远程试验数据与记录——IPEhub2与IPEmotion APP
    pandas教程:Data Aggregation 数据聚合
    Jmeter(五十四) - 从入门到精通高级篇 - 如何在linux系统下运行jmeter脚本 - 上篇(详解教程)
    win10 家庭版安装软件报错:无法成功安装操作,因为文件包含病毒或潜在的垃圾软件
  • 原文地址:https://blog.csdn.net/qq_16186465/article/details/125555628