有一个需求是要把Excel的数据导入到QT的Table Widget表格中。我是一个QT新手,在网上找了很多方法,在这里汇总记录一下。
目前总共有四种方法:
一、ODBC 导入
二、QAxObject 导入
三、QXlsx 导入
四、复制导入
其中方法一至三
适用于不加密的Excel文件,如果公司的Excel文件是加密过的,这三个方法是处理不了的,在我使用时是这样,如果有大佬懂的话请多指教。复制导入
是加密的Excel也能处理的,除非连复制黏贴都加密了,那真是离谱。
首先需要确认是否存在处理Excel的DSN
我们可以在C:\Windows\SysWOW64
文件夹中找到odbcad32.exe
,打开
如果有下面这个就可以了,没有的话看看添加里面有没有,还是没有就再找其他文章安装对应的东西吧,这里就不扩展了
然后就直接写代码就好了,先随便建个QT项目,随便搞个界面
#include
#include
#include
#include
#include
#include
#include
#include
随便在界面中加个按钮,然后创建一个**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();
}
使用ODBC时,Excel中的数据格式:
第一行是字段名,格式比较固定
这个需要在.pro文件中加入axcontainer
头文件中需要加入
#include
#include
#include
#include
#include
代码:
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;
}
wps使用的是ket.Application
使用这个时Excel表格的数据格式是这样的:
不需要第一行那个字段名了,直接全是数据就行,但是这种方法处理的速度很慢,可以说是四种方法中最慢的了
这是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
下载完成就是一个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)
#include "xlsxdocument.h"
#include "xlsxchartsheet.h"
#include "xlsxcellrange.h"
#include "xlsxchart.h"
#include "xlsxrichstring.h"
#include "xlsxworkbook.h"
using namespace QXlsx;
完整代码:
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开始的
这种方法的代码量比前面的少,看起来很简洁,速度也快
我用上面的三种方法都发现无法处理公司的加密Excel。虽然可以先解密再导入,但是解密要申请太麻烦了,所以我就想到这种逆天的做法:直接手动复制Excel中想要导入的内容,然后处理系统剪切板中复制到的内容形成一个数组,再依次绘制在表格中,这样就不用管加不加密了。不过面对连复制黏贴都加密的,也是没用的。而且逼格看起来就没用前面那些看起来高级,显得有点low,哈哈哈
需要导入的头文件:
//获取剪切板内容
#include
#include
#include
#include
代码:
void MainWindow::on_pushButton_4_clicked()
{
//获取剪切板内容
QClipboard *clipboard = QApplication::clipboard();
QString copyContent = clipboard->text();
//更新 2022-08-03 :在实际应用中出现复制到粘贴板的数据是以"\n"和"\t"连接,少了一个空格,所以会有两种情况
//我们需要先判断能否使用" \n"分割,若不匹配则改为使用"\n"分割
QString regex1 = " \n";
QString regex2 = " \t";
if (copyContent.split(" \n").size() <= 1)
{
regex1 = "\n";
regex2 = "\t";
}
QStringList splitList = copyContent.split(regex1);
QStringList dataList;
for (int i = 0; i < splitList.size() - 1; i++)
{
dataList.append(splitList.at(i).split(regex2));
}
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);
}
}
}
剪切板中的内容是这样的:
注意:可能会出现"\t","\n"
前面没有空格的情况
"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"
所以就先用 \n
来分割成每一行,再用 \t
分割成每个单元格存入数组列表中,注意前面还有个空格
由于是复制的,所以数据在哪个位置都没问题
我这个操作是先手动复制数据,然后点击界面的按钮进行处理
ok,就这么多了,不知道大伙儿还有什么其他方法吗?如果对我这篇文章有不解和建议的话,可以直接评论或者私信我哦。
这个演示的项目下载地址(免费的免费的)
https://download.csdn.net/download/qq_16186465/85847594
QXlsx资源下载地址(这是我自己上传的,也可以去github正版官网下)
https://download.csdn.net/download/qq_16186465/85847616