Article directory
1. Background
There is no official library for operating Excel in QT. This article introduces the ActiveX object (QAxObject) of the Windows system to operate Excel.
Of course, there are some open source libraries that can be used to operate Excel. For details, see: Some libraries for Qt processing Excel
This article only explains how QAxObject reads Excel.
2. Introduction
First of all, let's explain some concepts first, so that we can understand the basic process of Qt operating excel.
In Qt, QAxObject encapsulates COM objects, QAObject is derived from QAxBase, and QAxBase provides a set of APIs to directly access COM objects through IUnknown pointers. The specific structure is shown in the figure below.
The Excel we want to operate is also a COM object, so the operation on Excel can be realized in the above-mentioned way.
Before the specific operation, let's take a look at the hierarchical structure of excel, as shown in the figure, Application object –> Workbook object –> Worksheet object –> Range object.
An excel has an Application object, and an Application object consists of multiple workbook objects. These workbook objects are managed by the workbooks object. The workbook object contains several worksheets. These worksheet objects are managed by the worksheets object. The range object under the worksheet , corresponding to the table unit in this worksheet.
Basic operation method
get object
The above objects generally obtain a sub-object through QAxObject
the querySubObject()
method, for example:
QAxObject *excel = new QAxObject("Excel.Application");
QAxObject *workbooks = excel->querySubObject("WorkBooks");
QAxObject *workbook = workbooks->querySubObject("Open(QString&)", path);
QAxObject *sheets = workbook->querySubObject("Sheets");
QAxObject *sheet = sheets->querySubObject("Item(int)", 1);
QAxObject *range = sheet->querySubObject("Cells(int,int)", row, col);
The objects obtained in turn are:
- An Excel
Application
object. - An object that manages
Workbook
objectsWorkbooks
. path
The object corresponding to the Excel file whose path isWorkbook
.- The object that manages the worksheets within
Sheet
itSheets
. - The object corresponding to the first worksheet
Sheet
. - The object of the table cell at row
row
and column .col
range
call dynamic method
You can also dynamicCall()
call some actions through the method, such as:
workbook->dynamicCall("SaveAs(const QString &)", QDir::toNativeSeparators(path));
This is the call to save as path
path.
workbook->dynamicCall("Save()");
This is called save.
range->dynamicCall("Value", value);
This sets the value of the cell.
excel->dynamicCall("SetVisible(bool)", false);
This is set to be invisible when Excel is opened (that is, in the background).
workbooks->dynamicCall("Add");
This is to create a new Excel file.
workbooks->dynamicCall("Close()");
excel->dynamicCall("Quit()");
This is closing the Excel application.
In addition, there are many similar methods.
Set and get properties
Generally setProperty()
set properties through the method, such as:
range->setProperty("VerticalAlignment", -4108);
range->setProperty("HorizontalAlignment", -4108);
range->setProperty("WrapText", true);
range->setProperty("MergeCells", true);
range->setProperty("Bold", isBold);
Set up the cells respectively:
- Center vertically.
- Centered horizontally.
- Text wraps automatically.
- Cells are merged.
- The font is bold.
And if you want to get attributes, you can use property()
the method, which will return an QVariant
object, which can be converted to the basic type of Qt through methods such as toString()
, toInt()
etc. according to your needs.
More related
In addition to the above mentioned, more methods can go directly to Microsoft's official website to view documents .
3. Requirements for use
add module
To use QAxObject in Qt Creator, you need to add in pro first:
QT += axcontainer
Include the header file ActiveQt/QAxObject
#include <QAxObject>
How to connect with excel com
QAxObject *excel = new QAxObject("Excel.Application"); //!建立excel操作对象,并连接Excel控件
excel->dynamicCall("SetVisible (bool Visible)", "false"); //! 设置为不显示窗体
excel->setProperty("DisplayAlerts", false); //! 不显示任何警告信息, 如关闭时的是否保存提示
excel->dynamicCall("Quit(void)"); //! 关闭excel程序,操作完后记着关闭,由于是隐藏在后台进程中,不关闭进程会有很多excel.exe。
workbook->dynamicCall("Close(Boolean)", false); //! 关闭exce程序先关闭.xls文件
Basic operation of Excel
Only simple read and write operations are introduced, and operations such as modifying the cell format are required, please refer to "Excel VBA Reference Manual.chm"
Excel file operation
Get the collection of the current workbook. It should be noted here that the workbook is an Excel file.
QAxObject *workbooks = excel->querySubObject("Workbooks"); //! 获取工作簿(excel文件)集合
Create a new workbook , create a new workbook is to create a new Excel file
workbooks->synamicCall("Add"); //新建一个工作簿
QAxObject *workbook = excel->querySubObject("ActiveWorkBook"); //! 获取当前工作簿
To open an existing workbook is to open an Excel file
QString filename = "e:/123.xlsx";
QAxObject* workbook = workbooks->querySubObject("Open(const QString&)", filename);
save workbook
workbook->dynamicCall("Save()"); //!保存文件
workbook->dynamicCall("Close(Boolean)", false); //! 关闭文件
excel->dynamicCall("Quit()"); //! 关闭excel
save as workbook
QDir::toNativeSeparators,将路径中的"/"转换为"\",否则无法保存,"/"只是qt中可以识别
workbook->dynamiCall("SaveAs(const QString&)", QDit::toNativeSeparators(filename));
workbook->synamicCall("Close(Boolean)", false); //! 关闭文件
excel->dynamicCall("Quit()"); //! 关闭excel
Sheet worksheet operation
get all worksheets
QAxObject *worksheets = workbook->querySubObject("Sheets"):
Get a certain worksheet according to the serial number , the serial number order is the sorting at the bottom after excel is opened
QAxObject *worksheet = worksheets->querySubObejct("Item(int)", 1);
Get the number of rows and columns in the table
QAxObject* usedrange = worksheet->querySubObject("UsedRange"); //! sheet 范围
int intRowStart = usedrange->property("Row").toInt(); //! 起始行数
int intColStart = usedrange->property("Column").toInt(); //! 起始列数
QAxObject *rows, *columns;
rows = usedrange->querySubObject("Rows"): //! 行
columns = usedrange->querySubObject("Columns"); //! 列
int intRow = rows->property("Count").toInt(); //! 行数
int intCol = columns->property("Count").toInt(); //! 列数
content manipulation
Data Content Manipulation – Get Cell – Based on Coordinates
QAxObject *cell = worksheet->querySubObject("Cells(int, int)", i, j);
Data content operation – get cell – based on row and column names
QAxObject *cell = worksheet->querySubObject("Range(QVariant, QVariant)", "A1");
Data content manipulation – read cell content
QVariant cell_value = cell->property("Value");
Data content operation -- write cell content
cell->setProperty("Value", "内容");
Large amount of data read
Read all cell content - the amount of data is large, only one operation is required to read all the content, avoiding repeated QAxObect operations on each cell
QVariant var;
QAxObject * usedRange = sheet->querySubObject("UseRange"); //! 获取用户区域范围
if(NULL == usedRange || usedRange->isNull())
{
return var;
}
var = usedRange->dynamicCall("Value"); // 读取区域内所有值
delete usedRange;
At this time, the result is saved in QVariant, which needs to be converted into QList<QList> by itself
QList<QList<QVariant>> excel_list;
auto rows = var.toList();
for(auto row:rows)
{
excel_list.append(row.toList());
}
big data writing
Stored in QList<QList>, need to limit the range
QAxObject *user_rang = this->sheet->querySubObject("Rang(const QString&)", "A1:D100");
data input
rang->setProperty("Value", var);
4. Specific instructions for use
Generally, we use QAxObject to operate Excel into the following steps:
- Connect ControlExcel
- Open workbook (new or open Excel file)
- open sheet
- Get the number of rows and columns
- read and write
- set style
- save document
- Save as
- close file
Next, we will explain in detail how to complete the above operation.
1:连接控件Excel
2: 打开工作簿(新建或打开Excel文件)
3: 打开sheet
4: 获取行数,列数
5: 读和写
6:设置样式
7: 保存文件
8:另存为
9:关闭文件
1:连接控件Excel
QAxObject excel("Excel.Application");//连接Excel控件
excel.setProperty("Visible", false);// 不显示窗体
excel->setProperty("DisplayAlerts", false); // 不显示任何警告信息。如果为true, 那么关闭时会出现类似"文件已修改,是否保存"的提示
2: 打开工作簿(新建或打开Excel文件)
QAxObject* workbooks = excel->querySubObject("WorkBooks"); // 获取工作簿集合
2.1新建
workbooks->dynamicCall("Add"); // 新建一个工作簿
QAxObject* workbook = excel->querySubObject("ActiveWorkBook"); // 获取当前工作簿
2.2打开
QAxObject* workbook = workbooks->querySubObject("Open(const QString&)", ("C:/Users/lixc/Desktop/tt2.xlsx"));//Excel文件地址
3: 打开sheet
QAxObject* worksheet = workbook->querySubObject("WorkSheets(int)", 1); // 获取工作表集合的工作表1, 即sheet1
4: 获取行数,列数
QAxObject* usedrange = worksheet->querySubObject("UsedRange"); // sheet范围
int intRowStart = usedrange->property("Row").toInt(); // 起始行数 为1
int intColStart = usedrange->property("Column").toInt(); // 起始列数 为1
QAxObject *rows, *columns;
rows = usedrange->querySubObject("Rows"); // 行
columns = usedrange->querySubObject("Columns"); // 列
int intRow = rows->property("Count").toInt(); // 行数
int intCol = columns->property("Count").toInt(); // 列数
qDebug()<<"intRowStart:"<<intRowStart<<"\t intColStart"<<intColStart;
qDebug()<<"intRow"<<intRow<<"\t intCol"<<intCol;
5: 读和写
5.1读取单元格方式1
for(int i=intRowStart;i<intRow+intRowStart;i++)
{
for(int j=intColStart;j<intCol+intColStart;j++)
{
QAxObject* cell = worksheet->querySubObject("Cells(int, int)", i, j); //获单元格值
qDebug() << i << j << cell->dynamicCall("Value2()").toString();
}
}
5.2读取单元格方式2
QString X = "A2"; //设置要操作的单元格,A1
QAxObject* cellX = worksheet->querySubObject("Range(QVariant, QVariant)", X); //获取单元格
qDebug() << cellX->dynamicCall("Value2()").toString();
5.3写单元格方式1
cellX->dynamicCall("SetValue(conts QVariant&)", 100); // 设置单元格的值
5.4写单元格方式2
QAxObject *cell_5_6 = worksheet->querySubObject("Cells(int,int)", 5, 6);
cell_5_6->setProperty("Value2", "Java");
6:设置样式(未测试)
//获得单元格对象
QAxObject* cell = worksheet->querySubObject("Cells(int, int)", i, j);
6.1设置单元格内容的显示setProperty()
cell->setProperty("Value", "Java C++ C# PHP Perl Python Delphi Ruby"); //设置单元格值
cell->setProperty("RowHeight", 50); //设置单元格行高
cell->setProperty("ColumnWidth", 30); //设置单元格列宽
cell->setProperty("HorizontalAlignment", -4108); //左对齐(xlLeft):-4131 居中(xlCenter):-4108 右对齐(xlRight):-4152
cell->setProperty("VerticalAlignment", -4108); //上对齐(xlTop)-4160 居中(xlCenter):-4108 下对齐(xlBottom):-4107
cell->setProperty("WrapText", true); //内容过多,自动换行
cell->dynamicCall("ClearContents()"); //清空单元格内容
6.2设置单元格的样式 QAxObject* interior = cell->querySubObject("Interior");
QAxObject* interior = cell->querySubObject("Interior");
interior->setProperty("Color", QColor(0, 255, 0)); //设置单元格背景色(绿色)
QAxObject* border = cell->querySubObject("Borders");
border->setProperty("Color", QColor(0, 0, 255)); //设置单元格边框色(蓝色)
QAxObject *font = cell->querySubObject("Font"); //获取单元格字体
font->setProperty("Name", QStringLiteral("华文彩云")); //设置单元格字体
font->setProperty("Bold", true); //设置单元格字体加粗
font->setProperty("Size", 20); //设置单元格字体大小
font->setProperty("Italic", true); //设置单元格字体斜体
font->setProperty("Underline", 2); //设置单元格下划线
font->setProperty("Color", QColor(255, 0, 0)); //设置单元格字体颜色(红色)
6.3合并拆分单元格
QString merge_cell;
merge_cell.append(QChar(3 - 1 + 'A')); //初始列
merge_cell.append(QString::number(5)); //初始行
merge_cell.append(":");
merge_cell.append(QChar(5 - 1 + 'A')); //终止列
merge_cell.append(QString::number(8)); //终止行
QAxObject *merge_range = work_sheet->querySubObject("Range(const QString&)", merge_cell);
//merge_range 可以设置单元格属性
merge_range->setProperty("MergeCells", true); //合并单元格
//merge_range->setProperty("MergeCells", false); //拆分单元格
7: 保存文件
7.1保存当前文件(根据已经打开的工作簿,如果工作簿是新建的文件保存默认存储于Document文件夹中)
workbook->dynamicCall("Save()"); //保存文件
7.2指定目录存储
QString fileName = QFileDialog::getSaveFileName(NULL, QStringLiteral("保存文件"), QStringLiteral("excel名称"), QStringLiteral("EXCEL(*.xlsx)"));
//QString fileName=QStringLiteral("C:/Users/lixc/Desktop/excel名称.xlsx");
workbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(fileName)); //保存到filepath
// 注意一定要用QDir::toNativeSeparators, 将路径中的"/"转换为"\", 不然一定保存不了
9:关闭文件
workbook->dynamicCall("Close (Boolean)", false); //关闭文件
excel.dynamicCall("Quit(void)"); //退出
如果excel存在于堆上,注意手动释放
delete excel;
注意:调试过程中出现异常:需要打开任务管理器,结束Excle进程
//获得单元格对象
QAxObject* cell = worksheet->querySubObject("Cells(int, int)", i, j);
5. Project actual combat
After understanding the general steps of use, we can use it comprehensively through actual projects.
Practical project 1
The project code is as follows:
//#include <QtGui/QApplication>
#include <QApplication>
#include "mainwindow.h"
#include <QAxObject>
#include <QAxWidget>
#include <QTextCodec>
#include <QtDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB18030"));
// QTextCodec::setCodecForLocale(QTextCodec::codecForName("GB18030"));
// QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030"));
QAxWidget excel("Excel.Application");
excel.setProperty("Visible", true);
QAxObject * workbooks = excel.querySubObject("WorkBooks");
if (!workbooks) return 1; //错误返回,用 if(!excel)则不行
workbooks->dynamicCall("Open (const QString&)", QString("E:\\wenjian\\cs\\code\\QT\\testExcel2\\test.xlsx"));
QAxObject * workbook = excel.querySubObject("ActiveWorkBook"); //5) 获取活动工作簿:
QAxObject * worksheets = workbook->querySubObject("WorkSheets"); //获取所有的工作表:
int intCount = worksheets->property("Count").toInt(); //获取工作表数量:
qDebug() << "工作表数量" << intCount;
for (int i = 1; i <= intCount; i++)
{
int intVal;
QAxObject * worksheet = workbook->querySubObject("Worksheets(int)", i); //获取第i个工作表:
qDebug() << i << worksheet->property("Name").toString();
QAxObject * range = worksheet->querySubObject("Cells(1,1)"); //获取cell的值:
intVal = range->property("Value").toInt();
range->setProperty("Value", QVariant(intVal+1));
QAxObject * range2 = worksheet->querySubObject("Range(C1)");
intVal = range2->property("Value").toInt();
range2->setProperty("Value", QVariant(intVal+1));
}
QAxObject * worksheet = workbook->querySubObject("Worksheets(int)", 1);
QAxObject * usedrange = worksheet->querySubObject("UsedRange");
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();
qDebug() << "表格行数" << intRows;
qDebug() << "表格列数" << intCols;
// for (int i = intRowStart; i < intRowStart + intRows; i++)
// {
// for (int j = intColStart; j <= intColStart + intCols; j++)
// {
// QAxObject * range = worksheet->querySubObject("Cells(int,int)", i, j );
// qDebug() << i << j << range->dynamicCall("Value2()").toString(); //property("Value");不行
// }
// }
for (int i = intRowStart; i < intRows; i++)
{
for (int j = intColStart; j < intCols; j++)
{
QAxObject * range = worksheet->querySubObject("Cells(int,int)", i, j );
qDebug() << i << j << range->dynamicCall("Value2()").toString(); //property("Value");不行
}
}
excel.setProperty("DisplayAlerts", 0);
//qDebug("here?");
workbook->dynamicCall("SaveAs (const QString&)", QString("E:\\wenjian\\cs\\code\\QT\\testExcel2\\temp.xls"));//这里只能用相对路径!!!用绝对路径就报下面的错误。
excel.setProperty("DisplayAlerts", 1);
workbook->dynamicCall("Close (Boolean)", false);
excel.dynamicCall("Quit (void)");
MainWindow w;
w.show();
return a.exec();
}
The contents of test.xlsx are as follows:
[External link image transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the image and upload it directly (img-VWR6lCEv-1677385787835) (C:\Users\10521\AppData\Roaming\Typora\typora-user-images\ image-20230226101051423.png)]
Executing the code will print the following information:
[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-ZMXaMuYv-1677385787836) (C:\Users\10521\AppData\Roaming\Typora\typora-user-images\ image-20230226101140437.png)]
Explain that the code reads and prints the contents of the Excel table.
Practical project 2
The specific operation process is as follows:
QAxWidget excel(“Excel.Application”);
- Show current window:
excel.setProperty(“Visible”, true); - Change the Excel title bar:
excel.setProperty(“Caption”, “Invoke Microsoft Excel”); - Add new workbook:
QAxObject * workbooks = excel.querySubObject(“WorkBooks”);
workbooks->dynamicCall(“Add”); - Open an existing workbook:
workbooks->dynamicCall(“Open (const QString&)”, QString(“c:/test.xls”)); - Get the active workbook:
QAxObject * workbook = excel.querySubObject(“ActiveWorkBook”); - Get all worksheets:
QAxObject * worksheets = workbook->querySubObject(“WorkSheets”); - Get the number of worksheets:
int intCount = worksheets->property(“Count”).toInt(); - Get the first worksheet:
QAxObject * worksheet = workbook->querySubObject(“Worksheets(int)”, 1); - Get the value of the cell:
QAxObject * range = worksheet->querySubObject(“Cells(int,int)”, 1, 1 );
The project code is as follows:
#include <QApplication>
#include <QDir>
#include <QDebug>
//#include <QAxBase>
#include "mainwindow.h"
#include <QAxObject>
int main(int argc, char **argv)
{
QApplication a(argc, argv);
QAxObject excel("Excel.Application");
excel.setProperty("Visible", false);
QAxObject * workbooks = excel.querySubObject("WorkBooks");
workbooks->dynamicCall("Open (const QString&)", QString("E:\\wenjian\\cs\\code\\QT\\testExcel3\\test.xlsx"));
QAxObject * workbook = excel.querySubObject("ActiveWorkBook");
QAxObject * worksheets = workbook->querySubObject("WorkSheets");
int intCount = worksheets->property("Count").toInt();
QAxObject * worksheet = workbook->querySubObject("Worksheets(int)", 1);
QAxObject * usedrange = worksheet->querySubObject("UsedRange");
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();
qDebug() << "开始行数" << intRowStart;
qDebug() << "开始列数" << intColStart;
qDebug() << "总行数" << intRows;
qDebug() << "总列数" << intCols;
for (int i = intRowStart; i < intRowStart + intRows; i++)
{
for (int j = intColStart; j < intColStart + intCols; j++)
{
QAxObject * range = worksheet->querySubObject("Cells(int,int)", i, j );
qDebug() << i << j << range->property("Value");
}
}
excel.setProperty("DisplayAlerts", 0);
workbook->dynamicCall("SaveAs (const QString&)", QDir::toNativeSeparators("E:\\wenjian\\cs\\code\\QT\\testExcel3\\temp.xlsx"));
excel.setProperty("DisplayAlerts", 1);
workbook->dynamicCall("Close (Boolean)", false);
excel.dynamicCall("Quit (void)");
return a.exec();
}
The Excel file to be operated is consistent with that in the actual combat project 1.
Execute the code to print information as follows:
[External link picture transfer failed, the source site may have an anti-theft link mechanism, it is recommended to save the picture and upload it directly (img-OIat4Y1r-1677385787836) (C:\Users\10521\AppData\Roaming\Typora\typora-user-images\ image-20230226102643579.png)]
Practical project 3
code show as below:
// 参考内容: https://blog.csdn.net/qq319923400/article/details/80149367
// https://www.cnblogs.com/lifexy/p/10743316.html
// https://www.cnblogs.com/lifexy/p/10743352.html
#include "widget.h"
#include <QApplication>
#include <QAxObject> // .pro需要添加: QT += axcontainer
#include <QFileDialog>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
QAxObject excel("Excel.Application"); // 关联excel
excel.setProperty("Visible", true); // 运行程序时要不要通过excel打开当前编辑的表格
excel.setProperty("DisplayAlerts", false); // excel关闭时是否询问要不要保存
//excel.setProperty("Caption", "Qt Excel"); // 类似于文件类型吧,感觉这个名称意义不大
QAxObject* workbooks = excel.querySubObject("WorkBooks");
workbooks->dynamicCall("Add"); // 增加一个excel表格,写两遍会打开两个不同的excel表格
QAxObject* workbook = excel.querySubObject("ActiveWorkBook");
QAxObject* worksheet = workbook->querySubObject("WorkSheets(QString)", "Sheet1"); // 通过sheet名获取sheet1
// QAxObject* worksheet = workbook->querySubObject("WorkSheets(int)", "1"); // 通过编号获取sheet1, 结果和上面一样
worksheet->setProperty("Name", "Shadow3D_1"); // 修改sheet名
// 行列相关查询
QAxObject* usedrange = worksheet->querySubObject("UsedRange");
int intRowStart = usedrange->property("Row").toInt();
int intColStart = usedrange->property("Column").toInt();
// 注意: 这里的行和列都是从1开始计数的
qDebug() << "intRowStart: " << intRowStart << "\tintColStart: " << intColStart;
// 查看已经使用的最大行数和最大列数
int intRow = usedrange->querySubObject("Rows")->property("Count").toInt();
int intCol = usedrange->querySubObject("Columns")->property("Count").toInt();
qDebug() << "Rows: " << intRow << "\tColumns: " << intCol;
// 写单元格
for(int i = 1; i < 10; i++)
for(int j = 1; j < 10; j++)
worksheet->querySubObject("Cells(int, int)", i, j)->setProperty("Value2", i+j);
// 查看已经使用的最大行数和最大列数
usedrange = worksheet->querySubObject("UsedRange"); // 当重新修改sheet后,必须重新获取UsedRange值才能得到最新的行数和列数。
QAxObject* rows = usedrange->querySubObject("Rows");
QAxObject* columns = usedrange->querySubObject("Columns");
qDebug() << rows << columns; // 不知道这个rows和columns的值表示什么意义,每次运行都不一样。。。
intRow = rows->property("Count").toInt();
intCol = columns->property("Count").toInt();
qDebug() << "Rows: " << intRow << "\tColumns: " << intCol;
// 读单元格
QAxObject* cell = worksheet->querySubObject("Cells(int, int)", 5, 5); // 获取单元格对象
QString cellStr = cell->dynamicCall("Value2()").toString();
qDebug() << "cell: " << cellStr; // "10"
qDebug() << "cell: " << cellStr.toUtf8().data(); // 10 ( QString 类型转换为 QByteArray,再转换成Char* )
// 单元格格式
cell = worksheet->querySubObject("Cells(int, int)", 11, 11);
cell->setProperty("Value", "bool setProperty(const char *name, const QVariant &value");
cell->setProperty("RowHeight", 50);
cell->setProperty("ColumnWidth", 30);
cell->setProperty("HorizontalAlignment", -4108); // left:-4131 center:-4108 right:-4152
cell->setProperty("VerticalAlignment", -4108); // left:-4161 center:-4108 right:-4107
cell->setProperty("WrapText", true); // 单元格内容多时自动换行
// cell>dynamicCall("ClearContents()"); // 清空单元格内容
// 设置颜色,字体
cell = worksheet->querySubObject("Cells(int, int)", 12, 12); // 获取单元格对象
cell->setProperty("Value", "Text");
QAxObject* interior = cell->querySubObject("Interior");
interior->setProperty("Color", QColor(0, 255, 0)); // 背景颜色: Green
QAxObject* border = cell->querySubObject("Borders");
border->setProperty("Color", QColor(0, 0, 255)); // 边框颜色: Blue
QAxObject* font = cell->querySubObject("Font");
font->setProperty("Name", QStringLiteral("华文彩云"));
font->setProperty("Bold", true);
font->setProperty("Size", 20);
font->setProperty("Italic", true);
font->setProperty("Underline", 3); // 下划线:2 双下划线:3
font->setProperty("Color", QColor(255, 0, 0)); // 字体颜色: Red
// 合并拆分单元格
QString merge_cell;
merge_cell.append(QChar('A'+20)); // 从第(20+1)列开始,因为'A'表示第一列
merge_cell.append(QString::number(15)); // 从第15行开始
merge_cell.append(":");
merge_cell.append(QChar('A'+21)); // 到(21+1)列结束
merge_cell.append(QString::number(16)); // 到第16列结束
QAxObject* merge_range = worksheet->querySubObject("Range(const QString&)", merge_cell);
merge_range->setProperty("MergeCells", true); // 合并单元格
// merge_range->setProperty("MergeCells", false); // 拆分单元格
// 文件保存
QString fileName = QFileDialog::getSaveFileName(NULL, QStringLiteral("Save File As"), QStringLiteral("Shadow3D"), QStringLiteral("EXCEL(*.xlsx | *.xls)"));
workbook->dynamicCall("SaveAs(conse QString&)", QDir::toNativeSeparators(fileName));
// 关闭文件
workbook->dynamicCall("Close(Boolean)", false);
// 退出excel
excel.dynamicCall("Quit(void)");
// delete excel; // 如果excel是通过new方式建立在堆上,要记得释放。
w.show();
return a.exec();
}
Combat Item 4
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <ActiveQt/QAxObject>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void OpenExcel();
void AddNewExcel();
void SaveAndClose();
int GetRowsCount();
QString GetCell(int row, int column);
QString GetCell(QString numer);
void SetCell(int row, int column, QString value);
void SetCell(QString number, QString value);
void SetCellColor(int row, int column, QColor color);
private:
Ui::Widget *ui;
QAxObject *m_pExcel;
QAxObject *m_pWorkBooks;
QAxObject *m_pWorkBook;
QAxObject *m_pWorkSheets;
QAxObject *m_pWorkSheet;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QDir>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, m_pExcel(nullptr)
, m_pWorkBooks(nullptr)
, m_pWorkBook(nullptr)
, m_pWorkSheets(nullptr)
, m_pWorkSheet(nullptr)
{
ui->setupUi(this);
// 连接excel 控件
m_pExcel = new QAxObject("Excel.Application");
// m_pExcel->setControl("Excel.Applicatio");
// 设置操作excel时不打开excel窗体
m_pExcel->dynamicCall("SetVisible(bool Visible)",false);
// 设置不显示任何警告信息
m_pExcel->setProperty("DisplayAlert",false);
}
// 打开已有的excel
void Widget::OpenExcel()
{
QString strExcelPath = "C:\\Users\\Qcx\\Desktop\\test.xlsx";
// 获取当前工作簿
m_pWorkBooks = m_pExcel->querySubObject("WorkBooks");
// 打开指定工作簿
m_pWorkBook = m_pWorkBooks->querySubObject("Open(const QString&)",strExcelPath);
if(m_pWorkBook)
{
qDebug()<<"Open Excel Success!";
}
// 获取sheets
m_pWorkSheets = m_pWorkBook->querySubObject("Sheets");
// 获取某个sheet
m_pWorkSheet = m_pWorkSheets->querySubObject("Item(int)",1);
}
// 创建新的Excel
void Widget::AddNewExcel()
{
// 获取当前工作簿
m_pWorkBooks = m_pExcel->querySubObject("WorkBooks");
m_pWorkBooks->dynamicCall("Add");
m_pWorkBook = m_pExcel->querySubObject("ActiveWorkBook");
m_pWorkSheets = m_pWorkBook->querySubObject("Sheets");
m_pWorkSheet = m_pWorkSheets->querySubObject("Item(int)",1);
}
// 保存并关闭Excel
void Widget::SaveAndClose()
{
QString strSavePath = "C:\\Users\\Qcx\\Desktop\\temp.xlsx";
// 保存文件,一定要将路径中的'/'转为'\\',前者只能被Qt识别
m_pWorkBook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(strSavePath));
// 关闭文件
m_pWorkBook->dynamicCall("Close()");
// 关闭excel
m_pExcel->dynamicCall("Quit()");
delete m_pExcel;
m_pExcel = nullptr;
}
// 获取行数
int Widget::GetRowsCount()
{
int iRows = 0;
QAxObject *pRows = m_pWorkSheet->querySubObject("Rows");
iRows = pRows->property("Count").toInt();
return iRows;
}
// 获取单元格内容,行号+列号
QString Widget::GetCell(int row, int column)
{
QAxObject *pCell = m_pWorkSheet->querySubObject("Range(int, int)", row, column);
return pCell->property("Value").toString();
}
// 获取单元格内容,单元格标号如: A1,C5
QString Widget::GetCell(QString number)
{
QAxObject *pCell = m_pWorkSheet->querySubObject("Range(QString)", number);
return pCell->property("Value").toString();
}
// 设置单元格内容,行号+列号
void Widget::SetCell(int row, int column, QString value)
{
QAxObject *pCell = m_pWorkSheet->querySubObject("Range(int, int)", row, column);
pCell->setProperty("Value", value);
}
// 设置单元格内容,单元格标号如: A1,C5
void Widget::SetCell(QString number, QString value)
{
QAxObject *pCell = m_pWorkSheet->querySubObject("Range(QString)", number);
pCell->setProperty("Value", value);
}
// 设置单元格颜色的方式与设置值的方式一样,都是先获取到单元格,再设置属性
void Widget::SetCellColor(int row, int column, QColor color)
{
QAxObject *pCell = m_pWorkSheet->querySubObject("Range(int, int)", row, column);
QAxObject *pInterior = pCell->querySubObject("Interior");
pInterior->setProperty("Color", color);
}
Widget::~Widget()
{
delete ui;
}
pits that may be encountered
When the shutdown operation was performed, there was obviously no error in the execution, and the pointer was not abnormal, but the Excel process was not killed. The situation I encountered was that the computer installed Foxit Reader, which would occupy the COM interface of Excel. There are two solutions:
1. Violent and simple, uninstall Foxit Reader directly;
2. Open Excel --> Options --> Add-Ins --> Management at the bottom --> Select COM Add-Ins --> Go to --> Uncheck FoxitReader PDF Creator COM Add-in.
Practical project 5-encapsulated library
Simple package code
head Fileexcelmanager.h
#ifndef EXCELMANGER_H
#define EXCELMANGER_H
#include <QWidget>
#include <QString>
#include <QAxObject>
#include <QDialog>
class ExcelManger : public QWidget
{
Q_OBJECT
public:
explicit ExcelManger(QWidget *parent = nullptr);
~ExcelManger();
protected:
static QAxObject *excel;
static QAxObject *workbooks;
static QAxObject *workbook;
static int count;
void new_excel(const QString&);
void open_excel(const QString&);
QString get_cell_value(QAxObject*, int, int);
QVariant get_range(QAxObject*, const QString&);
void set_cell_value(QAxObject*, int, int, const QString&);
void merge_cells(QAxObject*, const QString&);
void set_cell_font_bold(QAxObject *sheet, const QString &cell, bool isBold = true);
void set_cell_font_center(QAxObject *sheet, const QString &cell);
void set_rows_autofit(QAxObject *sheet, const QString &rows);
void set_cols_autofit(QAxObject *sheet, const QString &cols);
void save_excel();
void save_excel_as(const QString&);
void close();
void free_excel();
signals:
};
#endif // EXCELMANGER_H
implementation fileexcelmanager.cpp
#include "excelmanger.h"
#include <QDebug>
#include <QVariant>
#include <QFile>
#include <QDir>
#ifdef Q_OS_WIN
#include <windows.h>
#endif
QAxObject* ExcelManger::excel = nullptr;
QAxObject* ExcelManger::workbooks = nullptr;
QAxObject* ExcelManger::workbook = nullptr;
int ExcelManger::count = 0;
ExcelManger::ExcelManger(QWidget *parent) : QWidget(parent)
{
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
if ((count++) == 0)
{
excel = new QAxObject("Excel.Application", this->parent());
excel->dynamicCall("SetVisible(bool)", false);
workbooks = excel->querySubObject("WorkBooks");
}
}
ExcelManger::~ExcelManger()
{
if ((--count) == 0)
free_excel();
}
void ExcelManger::new_excel(const QString &path)
{
workbooks->dynamicCall("Add");
workbook = excel->querySubObject("ActiveWorkBook");
save_excel_as(path);
}
void ExcelManger::open_excel(const QString &path)
{
close();
QFile file(path);
if (!file.exists())
new_excel(path);
else
workbook = workbooks->querySubObject("Open(QString&)", path);
file.close();
}
QString ExcelManger::get_cell_value(QAxObject *sheet, int row, int col)
{
QAxObject *range = sheet->querySubObject("Cells(int,int)", row, col);
return range->property("Value").toString();
}
QVariant ExcelManger::get_range(QAxObject *sheet, const QString &range)
{
return sheet->querySubObject("Range(const QString&)", range)->property("value");
}
void ExcelManger::set_cell_value(QAxObject *sheet, int row, int col, const QString& value)
{
QAxObject *range = sheet->querySubObject("Cells(int,int)", row, col);
range->dynamicCall("Value", value);
}
void ExcelManger::merge_cells(QAxObject *sheet, const QString &cell)
{
QAxObject *range = sheet->querySubObject("Range(const QString&)", cell);
range->setProperty("VerticalAlignment", -4108);
range->setProperty("WrapText", true);
range->setProperty("MergeCells", true);
}
void ExcelManger::set_cell_font_bold(QAxObject *sheet, const QString &cell, bool isBold)
{
QAxObject *range = sheet->querySubObject("Range(const QString&)", cell);
range = range->querySubObject("Font");
range->setProperty("Bold", isBold);
}
void ExcelManger::set_cell_font_center(QAxObject *sheet, const QString &cell)
{
QAxObject *range = sheet->querySubObject("Range(const QString&)", cell);
range->setProperty("HorizontalAlignment", -4108);
range->setProperty("VerticalAlignment", -4108);
}
void ExcelManger::set_rows_autofit(QAxObject *sheet, const QString &rows)
{
QAxObject *Rows = sheet->querySubObject("Rows(const QString &)", rows);
Rows->dynamicCall("AutoFit()");
}
void ExcelManger::set_cols_autofit(QAxObject *sheet, const QString &cols)
{
QAxObject *Cols = sheet->querySubObject("Columns(const QString &)", cols);
Cols->dynamicCall("AutoFit()");
}
void ExcelManger::save_excel_as(const QString &path)
{
if (workbook)
workbook->dynamicCall("SaveAs(const QString &)", QDir::toNativeSeparators(path));
}
void ExcelManger::save_excel()
{
if (workbook)
workbook->dynamicCall("Save()");
}
void ExcelManger::close()
{
if (workbook)
workbook->dynamicCall("Close()");
}
void ExcelManger::free_excel()
{
if (excel != nullptr)
{
workbooks->dynamicCall("Close()");
excel->dynamicCall("Quit()");
delete workbook;
delete workbooks;
delete excel;
excel = nullptr;
workbooks = nullptr;
workbook = nullptr;
}
}
Among the existing functions are mainly:
new_excel()
: Create a new table file according to the given directory.open_excel()
: Open the table file according to the given directory.get_cell_value()
: Get the cell value of a row and a column in the specified worksheet (the return type isQString
).set_cell_value()
: Set the cell value of a row and a column in the specified worksheet (the setting type isQString
).save_excel()
andsave_excel_as()
: save the file and save as path.close()
andfree_excel()
: close the file andApplication
.- And some basic cell style settings, more functions to be added.
other
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
It needs to COM
be initialized with this function before using the interface .
Static members are used in the program to ensure that only one Excel application is running in the background when multiple worksheets are manipulated.
Of course, in order to achieve this goal, the program also needs to ensure that each object can be correctly destructedExcelManger
when it is used .
Project combat 6-encapsulated library
exceloperator.h
#ifndef EXCELOPERATOR_H
#define EXCELOPERATOR_H
#include <QObject>
#include <ActiveQt/QAxObject>
#include <QDebug>
#include <QDir>
class ExcelOperator : public QObject
{
Q_OBJECT
public:
explicit ExcelOperator(QObject *parent = nullptr);
~ExcelOperator();
//打开文件
bool open(QString path);
//关闭文件
bool close();
//获取工作表数量
int getSheetsCount();
//根据名称创建工作表
QAxObject* addSheet(QString name);
//根据名称删除工作表
bool delSheet(QString name);
//根据编号删除工作表
bool delSheet(int index);
//根据名称获取工作表
QAxObject* getSheet(QString name);
//根据编号获取工作表
QAxObject* getSheet(int index);
//获取行对象
QAxObject* getRows(QAxObject* pSheet);
//获取行数
int getRowsCount(QAxObject* pSheet);
//获取列对象
QAxObject* getColumns(QAxObject* pSheet);
//获取列数
int getColumnsCount(QAxObject* pSheet);
//根据行列值获取单元格值, 如: 3行,5列
QString getCell(QAxObject* pSheet, int row, int column);
//根据行列编号获取单元格值, 如: "F6"
QString getCell(QAxObject* pSheet, QString number);
//根据行列值设置单元格值
bool setCell(QAxObject* pSheet, int row, int column, QString value);
//根据行列编号设置单元格值
bool setCell(QAxObject* pSheet, QString number, QString value);
signals:
public slots:
private:
QAxObject* m_pExcel;
QAxObject* m_pWorksheets;
QAxObject* m_pWorkbook;
QString m_strPath;
};
#endif // EXCELOPERATOR_H
exceloperator.c
#include "exceloperator.h"
#include <objbase.h>
ExcelOperator::ExcelOperator(QObject *parent) : QObject(parent)
, m_pExcel(NULL)
, m_pWorksheets(NULL)
, m_pWorkbook(NULL)
{
}
ExcelOperator::~ExcelOperator()
{
close();
}
bool ExcelOperator::open(QString path)
{
m_strPath = path;
QAxObject *pWorkbooks = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
m_pExcel = new(std::nothrow) QAxObject();
if (NULL == m_pExcel) {
qCritical()<<"创建Excel对象失败...";
return false;
}
try {
m_pExcel->setControl("Excel.Application");
m_pExcel->dynamicCall("SetVisible(bool)", false); //true 表示操作文件时可见,false表示为不可见
m_pExcel->setProperty("DisplayAlerts", false);
pWorkbooks = m_pExcel->querySubObject("WorkBooks");
pWorkbooks->dynamicCall("Add");
m_pWorkbook = m_pExcel->querySubObject("ActiveWorkBook");
qDebug()<<"excel path: "<<m_strPath;
// 获取打开的excel文件中所有的工作sheet
m_pWorksheets = m_pWorkbook->querySubObject("WorkSheets");
} catch (...) {
qCritical()<<"打开文件失败...";
return false;
}
return true;
}
bool ExcelOperator::close()
{
qDebug()<<"excel close...";
if (m_pExcel)
{
qDebug()<<"closing...";
m_pWorkbook->dynamicCall("SaveAs(const QString&)", QDir::toNativeSeparators(m_strPath));
m_pWorkbook->dynamicCall("Close()");
m_pExcel->dynamicCall("Quit()");
delete m_pExcel;
m_pExcel = NULL;
}
return true;
}
int ExcelOperator::getSheetsCount()
{
int count = 0;
count = m_pWorksheets->property("Count").toInt();
return count;
}
QAxObject* ExcelOperator::addSheet(QString name)
{
QAxObject *pWorkSheet = NULL;
try {
int count = m_pWorksheets->property("Count").toInt(); //获取工作表数目
QAxObject *pLastSheet = m_pWorksheets->querySubObject("Item(int)", count);
pWorkSheet = m_pWorksheets->querySubObject("Add(QVariant)", pLastSheet->asVariant());
pLastSheet->dynamicCall("Move(QVariant)", pWorkSheet->asVariant());
pWorkSheet->setProperty("Name", name); //设置工作表名称
} catch (...) {
qCritical()<<"创建sheet失败...";
}
return pWorkSheet;
}
bool ExcelOperator::delSheet(QString name)
{
try {
QAxObject *pFirstSheet = m_pWorksheets->querySubObject("Item(QString)", name);
pFirstSheet->dynamicCall("delete");
} catch (...) {
qCritical()<<"删除sheet失败...";
return false;
}
return true;
}
bool ExcelOperator::delSheet(int index)
{
try {
QAxObject *pFirstSheet = m_pWorksheets->querySubObject("Item(int)", index);
pFirstSheet->dynamicCall("delete");
} catch (...) {
qCritical()<<"删除sheet失败...";
return false;
}
return true;
}
QAxObject* ExcelOperator::getSheet(QString name)
{
QAxObject* pWorkSheet = NULL;
try {
pWorkSheet = m_pWorksheets->querySubObject("Item(QString)", name);
} catch (...) {
qCritical()<<"获取sheet失败...";
}
return pWorkSheet;
}
QAxObject* ExcelOperator::getSheet(int index)
{
QAxObject* pWorkSheet = NULL;
try {
pWorkSheet = m_pWorksheets->querySubObject("Item(int)", index);
} catch (...) {
qCritical()<<"获取sheet失败...";
}
return pWorkSheet;
}
QAxObject* ExcelOperator::getRows(QAxObject* pSheet)
{
QAxObject* pRows = NULL;
try {
pRows = pSheet->querySubObject("Rows");
} catch (...) {
qCritical()<<"获取行失败...";
}
return pRows;
}
int ExcelOperator::getRowsCount(QAxObject* pSheet)
{
int rows = 0;
try {
QAxObject* pRows = getRows(pSheet);
rows = pRows->property("Count").toInt();
} catch (...) {
qCritical()<<"获取行数失败...";
}
return rows;
}
QAxObject* ExcelOperator::getColumns(QAxObject* pSheet)
{
QAxObject* pColumns = NULL;
try {
pColumns = pSheet->querySubObject("Columns");
} catch (...) {
qCritical()<<"获取列失败...";
}
return pColumns;
}
int ExcelOperator::getColumnsCount(QAxObject* pSheet)
{
int columns = 0;
try {
QAxObject* pColumns = getColumns(pSheet);
columns = pColumns->property("Count").toInt();
} catch (...) {
qCritical()<<"获取列数失败...";
}
return columns;
}
QString ExcelOperator::getCell(QAxObject* pSheet, int row, int column)
{
QString strCell = "";
try {
QAxObject* pCell = pSheet->querySubObject("Cells(int, int)", row, column);
strCell = pCell->property("Value").toString();
} catch (...) {
qCritical()<<"获取单元格信息失败...";
}
return strCell;
}
QString ExcelOperator::getCell(QAxObject* pSheet, QString number)
{
QString strCell = "";
try {
QAxObject* pCell = pSheet->querySubObject("Range(QString)", number);
strCell = pCell->property("Value").toString();
} catch (...) {
qCritical()<<"获取单元格信息失败...";
}
return strCell;
}
bool ExcelOperator::setCell(QAxObject* pSheet, int row, int column, QString value)
{
try {
QAxObject* pCell = pSheet->querySubObject("Cells(int, int)", row, column);
pCell->setProperty("Value", value);
} catch (...) {
qCritical()<<"写入单元格信息失败...";
return false;
}
return true;
}
bool ExcelOperator::setCell(QAxObject* pSheet, QString number, QString value)
{
try {
QAxObject* pCell = pSheet->querySubObject("Range(QString)", number);
pCell->setProperty("Value", value);
} catch (...) {
qCritical()<<"写入单元格信息失败...";
return false;
}
return true;
}
Six, some tips
read data in excel
I said before how to save the data in Qt to excel, now let’s talk about how to read the data in excel to Qt (whether it is read into a table or saved into a data model, the core point is to convert excel The data in the container is read into the Qt container, and then as long as the data in the container can be read, it is very simple to save it to the table or the model later).
Suppose we already have such an excel sheet saved by Qt, and now we want to read the data in it
code show as below:
void Widget::on_readbtn_clicked()
{
QAxObject *excel = new QAxObject(this);//建立excel操作对象
excel->setControl("Excel.Application");//连接Excel控件
excel->setProperty("Visible", false);//显示窗体看效果,选择ture将会看到excel表格被打开
excel->setProperty("DisplayAlerts", true);//显示警告看效果
QAxObject *workbooks = excel->querySubObject("WorkBooks");//获取工作簿(excel文件)集合
QString str = QFileDialog::getOpenFileName(this,"打开",
QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation),"Excel 文件(*.xls *.xlsx)");
workbooks->dynamicCall("Open(const QString&)", str);//打开刚才选定的excel
QAxObject *workbook = excel->querySubObject("ActiveWorkBook");
QAxObject *worksheet = workbook->querySubObject("WorkSheets(int)",1);
QAxObject *usedRange = worksheet->querySubObject("UsedRange");//获取表格中的数据范围
QVariant var = usedRange->dynamicCall("Value");//将所有的数据读取刀QVariant容器中保存
QList<QList<QVariant>> excel_list;//用于将QVariant转换为Qlist的二维数组
QVariantList varRows=var.toList();
if(varRows.isEmpty())
{
return;
}
const int row_count = varRows.size();
QVariantList rowData;
for(int i=0;i<row_count;++i)
{
rowData = varRows[i].toList();
excel_list.push_back(rowData);
}//转换完毕
qDebug()<<excel_list.at(3).at(1).toInt();
//然后将二维数组Qlist<Qlist<QVariant>>中的数据读取出来,到表格或者数据模型中,具体在这里过程省略
workbook->dynamicCall( "Close(Boolean)", false );
excel->dynamicCall( "Quit(void)" );
delete excel;//因为前面选择了不显示excel窗口,如果这里不删除excel的话,excel依然是打开的,只是我们看不见(因为被隐藏起来了)
}
The line of code marked in red can be used to test whether the data in the two-dimensional array can be successfully read.
When qDebug()<<excel_list.at(3); is entered, the printed result is
Because there are a total of 24 columns in excel, but only 6 rows have data, so you can see that this is actually the data in the 4th row of the table (because it starts from zero 0, 1, 2, 3) all read out .
When qDebug()<<excel_list.at(3).at(3); is input, the printed result is
That is, the data in row 4 and column 4 is printed out.
When entering qDebug()<<excel_list.at(3).at(3).toInt();, the printed result is the number 3.
As a result, the work of reading excel is basically completed. As for how to save it in the form or model, it depends on your preference.
*Tips: Since the data saved in excel is read into the Qlist array, it is not necessarily a regular two-dimensional array, so if necessary, the first and second rows of excel can be reserved for saving information, these The information can be used to judge what rules to read when reading.