学习日记3:Qt将excel文件导入MySQL数据库,tableview数据导出至excel文件

本文详细介绍了如何使用Qt中的QAxObject和QXlsx库实现Excel文件的导入导出功能,包括将Excel数据导入MySQL,以及将tableview中的数据导出为Excel和直接显示Excel内容。同时提到了一些注意事项,如内存管理、文件名编码问题和SQL语句一致性要求。
摘要由CSDN通过智能技术生成


一、成果展示

在这里插入图片描述

本文实现的功能
以下两种功能用QAxObject 实现
1、点击导入按钮可将指定的excel文件中的所有sheet导入MySQL中,一个sheet一张表;
2、数据在tableview发生改变后,可导出成excel文件
以下功能用QXlsx
3、将excel文件内容直接显示到tableview上


二、 准备工作

Qt为我们提供了两个操作excel的类:QXlsx和QAxObject

1、关于QXlsx的准备工作,具体可看其它大佬教程
https://blog.csdn.net/qq_43627907/article/details/124175572

2、QAxObject 的相关操作流程
在这里插入图片描述
3、QAxObject 的常用函数
https://blog.csdn.net/aggie4628/article/details/102809700


三、代码示例

功能1

  • 点击导入按钮可将指定的excel文件中的所有sheet导入MySQL中,一个sheet一张表;

  • 需要注意的是在MySQL数据库中创建新表格时,是需要所有字段名的,所以我这里选择将excel文件的第一行单独取出来做了表头,同理在写excel文件时也要将tableview中的表头取出来。

//导入按钮
void MainWindow::on_pushButton_import_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this, tr("Open Excel file"), "", tr("Excel Files (*.xlsx *.xls)"));//打开选择文件窗口
    if (!filePath.isEmpty())
    {
        qDebug() << "当前打开的文件路径为"<<filePath;//显示文件路径
    }
    QAxObject *excel = new QAxObject("Excel.Application");
    excel->setProperty("Visible", false);// 不显示 Excel 窗体
    QAxObject *work_books = excel->querySubObject("WorkBooks"); //获取工作簿集合
    work_books->dynamicCall("Open (const QString&)", filePath);//打开已存在的工作簿
    QAxObject *work_book = excel->querySubObject("ActiveWorkBook");//获取当前工作簿

    QAxObject *work_sheets = work_book->querySubObject("Sheets");  //Sheets也可换用WorkSheets
    int sheet_count = work_sheets->property("Count").toInt();  //获取工作表数目
    qDebug() << "当前文件有"<<sheet_count<< "张sheet";

    for(int i=1; i<=sheet_count; i++)//循环操作每张sheet
    {
        QAxObject *work_sheet = work_book->querySubObject("Sheets(int)", i);
        QString work_sheet_name = work_sheet->property("Name").toString();  //获取工作表名称


        //查看数据库中是否有相应表格,没有就创建
        if(isTableExists(work_sheet_name))
        {
            int ok = QMessageBox::warning(this,tr("提示:"),tr("当前数据库中已经存在该表,"
                                                            "确认替换吗? "),QMessageBox::Yes,QMessageBox::No);
            if(ok == QMessageBox::No);
            else  //替换
            {
                QSqlQuery query(dbMYSQL);
                query.exec(QString("drop table if exists %1").arg(work_sheet_name));
                creatNewTable(work_sheet);
                InsertData(work_sheet);
            }
        }
        else
        {
            creatNewTable(work_sheet);
            InsertData(work_sheet);
        }
    }
    work_book->dynamicCall("Close()");//关闭工作簿
    excel->dynamicCall("Quit()");//关闭 excel
    delete excel;
    excel = NULL;
}
//判断表是否存在,存在为真,不存在为假
bool MainWindow::isTableExists(QString &table)
{
    QSqlQuery query(dbMYSQL);
    QString sql = QString("show tables;");  // 查询数据库中是否存在表名
    query.exec(sql);
    while(query.next())
    {
        QString biaoming=query.value(0).toString().trimmed();
        qDebug()<<"数据库中已存在:"<<biaoming;
        if(QString::compare(biaoming,table,Qt::CaseInsensitive));
        else//存在
            return true;
    }
    return false;
}


//在mysql中创建新表格
void MainWindow::creatNewTable(QAxObject *work_sheet)
{
    //获取表头
    QString work_sheet_name = work_sheet->property("Name").toString();  //获取工作表名称
    QAxObject *used_range = work_sheet->querySubObject("UsedRange");//选取当前页面所有已使用单元格
    QAxObject *columns = used_range->querySubObject("Columns");
    int column_start = used_range->property("Column").toInt();  //获取起始列
    int column_count = columns->property("Count").toInt();  //获取列数
    QString keyType[column_count];//表头数列

    for(int i = column_start;i < column_count+column_start;i ++)//获取表头
    {
        QAxObject *cell = work_sheet->querySubObject("Cells(int,int)",1, i);
        QString value = cell->dynamicCall("Value2()").toString();
        keyType[i-column_start] = value;
        qDebug() <<i-column_start<<":"<< keyType[i-column_start];
    }
    QString creatsql=QString("create table %1(").arg(work_sheet_name);//按表头在MySQL中创建新表
    for(int i=0;i<=column_count-1;i++)
    {
        creatsql=creatsql+QString("%1").arg(keyType[i]);
        if(i < column_count-1 )
        {
            creatsql =creatsql+ QString(" varchar(20),");
        }
        else
        {
            creatsql =creatsql+ QString(" varchar(20));");
        }
    }
    qDebug() << creatsql;
    QSqlQuery creatquery(dbMYSQL);
    if(creatquery.exec(creatsql))
        qDebug() << "成功创建表格:"<<work_sheet_name;
    else
        qDebug() << "创建表格"<<work_sheet_name<< "失败";
}


//在表格中插入数据
void MainWindow::InsertData(QAxObject *work_sheet)
{
    QString work_sheet_name = work_sheet->property("Name").toString();  //获取工作表名称
    QAxObject *used_range = work_sheet->querySubObject("UsedRange");//选取当前页面所有已使用单元格
    QAxObject *rows = used_range->querySubObject("Rows");
    QAxObject *columns = used_range->querySubObject("Columns");
    int row_start = used_range->property("Row").toInt();  //获取起始行
    int column_start = used_range->property("Column").toInt();  //获取起始列
    int row_count = rows->property("Count").toInt();  //获取行数
    int column_count = columns->property("Count").toInt();  //获取列数
    qDebug() << "column_count:"<<column_count;

    QSqlQuery insertquery(dbMYSQL);
    for(int i = row_start; i < row_count+row_start;i++)//从行开始
    {
        QString strSql = QString("insert into %1 values(").arg(work_sheet_name);
        for(int j = column_start; j < column_count+column_start;j++)
        {
            QAxObject *cell = work_sheet->querySubObject("Cells(int,int)", i+1, j);//去除第一行表头
            QString Value = cell->dynamicCall("Value2()").toString();
            strSql = strSql + QString("'%1'").arg(Value);
            if(j < column_count )
            {
                strSql = strSql + QString(",");
            }
            else
            {
                strSql = strSql + QString(")");
            }
        }
        qDebug()<<strSql;
        //调用写数据函数,将一行数据插入数据库
        insertquery.exec(strSql);
    }

    //验证是否缺少行,不缺少则数据导入成功
    QString resuresql=QString("select count(1) from %1").arg(work_sheet_name);//获取当前行数
    insertquery.exec(resuresql);
    insertquery.next();
    if(insertquery.value(0).toInt())
        QMessageBox::warning(this,tr("提示:"),tr("数据导入成功"));
    else
        QMessageBox::warning(this,tr("提示:"),tr("数据缺失,请重新导入"));
}

功能2

  • 将tableview中的数据取出,并保存至excel文件
void MainWindow::on_pushButton_export_clicked()
{
    QAxObject *excel = new QAxObject("Excel.Application");//创建了一个QAxObject对象,用于访问Excel应用程序的COM接口。
    if (excel->isNull())//判断是否存在excel
    {
        if (excel != NULL)//网络中很多使用 excel==NULL 判断,是错误的
        {
            excel->dynamicCall("Quit()");//关闭
            delete excel;
        }
        QMessageBox::critical(0, "错误信息", "没有找到 EXCEL 应用程序");
        return;
    }
    QAxObject *workbooks = NULL;
    QAxObject *workbook = NULL;
    QAxObject *worksheets = NULL;
    QAxObject *worksheet = NULL;
    excel->dynamicCall("SetVisible (bool)", true);//不显示窗体
    excel->setProperty("DisplayAlerts", false); //不显示任何警告信息。如果为 true 那么在关闭是会出现类似“文件已修改,是否保存” 的提示
    workbooks = excel->querySubObject("WorkBooks");//获取工作簿集合
    QString filePath = QFileDialog::getSaveFileName(this, tr("Save File"),"",tr("Excel Files (*.xlsx *.xls)"));
    if (QFile::exists(filePath))
    {
        workbook = workbooks->querySubObject("Open(const QString &)", filePath);
    }
    else
    {
        workbooks->dynamicCall("Add");//新建一个工作簿
        workbook = excel->querySubObject("ActiveWorkBook");//获取当前工作簿
    }
    worksheets = workbook->querySubObject("Sheets");//获取工作表集合
    worksheet = worksheets->querySubObject("Item(int)",1);//获取工作表集合的工作表 1,即sheet1
    QAxObject * usedrange = worksheet->querySubObject("UsedRange");//获取该 sheet 的使用范围对象
    QAxObject * rows = usedrange->querySubObject("Rows");
    QAxObject * columns = usedrange->querySubObject("Columns");
    int intRowStart = usedrange->property("Row").toInt();
    int intColStart = usedrange->property("Column").toInt();
    int intCols = columns->property("Count").toInt();
    int intRows = rows->property("Count").toInt();
    QAxObject *cell = NULL;
    int rowCount = ui->tableView->model()->rowCount();
    int colCount = ui->tableView->model()->columnCount();
    // 清空数据
    for(int i=intRowStart;i <intRowStart + intRows;i++)
    {
        for(int j=intColStart ;j<intColStart+intCols;j++)
        {
            cell = worksheet->querySubObject("Cells(int,int)", i,j ); //获取单元格
            cell->setProperty("Value", "");
        }
    }
    // 插入数据
    for (int i = intRowStart; i < intRowStart+rowCount; i++)
    {
        for(int j = intColStart; j < intColStart+colCount; j++)
        {
            QModelIndex indextemp = ui->tableView->model()->index(i-intRowStart, j-intColStart);
            QVariant str = ui->tableView->model()->data(indextemp);
            cell = worksheet->querySubObject("Cells(int,int)", i, j);//获取单元格
            cell->setProperty("Value", str);
        }
    }
    QMessageBox::information(this,"提示","数据导出完毕");
    workbook->dynamicCall("SaveAs(const QString&)",QDir::toNativeSeparators(filePath));//保存至 filepath,注意一定要用 QDir::toNativeSeparators 将路径中的"/"转换为"\",不然一定保存不了。
    qDebug() <<"保存路径为:"<< QDir::toNativeSeparators(filePath);
    workbook->dynamicCall("Close()");//关闭工作簿
    excel->dynamicCall("Quit()");//关闭 excel
    delete excel;
    excel = NULL;
}

功能3

  • 将excel文件内容直接显示到tableview上

1、先在.h文件中创建私有变量

    QXlsx::Document* m_xlsx = nullptr;

2、 .cpp文件

//导入数据,显示全部数据
void MainWindow::on_pushButton_import_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this, tr("Open Excel file"), "", tr("Excel Files (*.xlsx *.xls)"));
    if (!filePath.isEmpty())
    {
        ui->lineEdit_dir->setText(filePath);//显示文件路径
        if(!m_xlsx)
            m_xlsx = new QXlsx::Document(filePath,this);        // 打开EXCEL_NAME文件,将所有数据读取到内存中,然后关闭excel文件
        if(m_xlsx->load())  // 判断文件是否打开成功(也可以使用isLoadPackage),如果文件不存在则为false
            qDebug() << "excel打开并加载成功!";
        else
            qWarning() << "excel打开失败!";
      }
    if(!m_xlsx)  // 判断文件是否打开成功(也可以使用isLoadPackage),如果文件不存在则为false
    {
        QMessageBox::information(this,"提示","请先点击'打开文件'按钮");
        return;
    }
    rowLen = m_xlsx->dimension().rowCount();           // 获取最大行数
    columnLen = m_xlsx->dimension().columnCount();     // 获取最大列数
    qDebug() << "row:"<<rowLen<<"  column:"<<columnLen;

    QStandardItemModel *model = new QStandardItemModel();//QStandardItemModel 是包含单元格的容器(在这里可以看作表)
    for(int i = 1; i <= rowLen; i++)                       // 遍历每一行
    {
        QString data = QString("第%1行:").arg(i);
        for(int j = 1; j <= columnLen; j++)                // 遍历每一个单元格(列)
        {
            QVariant value = m_xlsx->read(i, j);  // 通过单元格行号、列号读取数据
            if(i==1)   // 将复选框显示出来
                if(j>3)
                {
                    QListWidgetItem *item = new QListWidgetItem();
                    QCheckBox *checkBox= new QCheckBox (value.toString(),this);

                    ui->listWidget->addItem(item);//在ListWidget中添加一个条目
                    ui->listWidget->setItemWidget(item, checkBox);//在这个条目中放置CheckBox
                }

            if(!value.isNull())
                data.append(value.toString()).append(" ");
            else
                data.append("NULL ");
            QStandardItem *item = new QStandardItem(value.toString());//QStandardItem是存储数据的单元格,它存储的是QString
            model->setItem(i-1, j-1, item);
        }
    }
    ui->tableView->setModel(model);//表视图,用于显示QStandardItemModel
}

四、小结

1、由于反复对excel文档进行操作,一查后台,发现开了很多个他的进程,可能会导致电脑卡顿,在查文章时看到以下文字,可能和卡顿有关,目前还未解决。

  • 需要注意的是上文代码中除了获取单元格范围 (UsedRange)操作之外,其余得到的都是该对象的引用,不会占用内存空间,不需要释放,而获取单元格适用范围 (UsedRange) 则得到一个 new出来新分配的对象,因此在读取或写入操作结束后需要手动释放该对象。

2、excel文件名中带有汉字时,会创建表格失败,可能和转码有关,加上上次的反引号也行不通,目前只能尽量避免使用汉字。

3、使用insert语句时,字段要和create语句的字段完全一致。


五、代码下载

链接:https://pan.quark.cn/s/8524a2134357
提取码:j9rX

  • 45
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值