
Qt 实践——如何用 Qt 操作 Excel
原理
用到的库和类
一般 Qt 操作 Excel 的方法都是基于 QAxObject,也就是采用 COM 接口。
QAxObject 继承自 QAxBase,其中提供了许多 API 通过对象指针访问 COM 对象,而 Excel 本身也是一个 COM 对象,因此可以用这个类操作 Excel。
层次结构
Excel 一般的主要层次结构分为:
Application对象。Workbook对象。Worksheet对象。Range对象。
Worksheet 对象相当于每个 Excel 文件的工作表,Range 对象则是其中的表格单元。
基本操作方法
获取对象
上述对象获取某个子对象一般通过 QAxObject 的 querySubObject() 方法,比如:
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);
这其中依次得到的对象分别是:
- Excel 的
Application对象。 - 管理
Workbook对象的Workbooks对象。 - 路径为
path的 Excel 文件对应的Workbook对象。 - 管理其中工作表
Sheet的Sheets对象。 - 第一张工作表对应的
Sheet对象。 - 其中第
row行,第col列的表格单元的range对象。
调用动态方法
还可以通过 dynamicCall() 方法调用一些动作,比如:
workbook->dynamicCall("SaveAs(const QString &)", QDir::toNativeSeparators(path));
这是调用另存为 path 路径。
workbook->dynamicCall("Save()");
这是调用保存。
range->dynamicCall("Value", value);
这时设置单元格的值。
excel->dynamicCall("SetVisible(bool)", false);
这是设置打开 Excel 时不可见(也就是后台进行)。
workbooks->dynamicCall("Add");
这是新建一个 Excel 文件。
workbooks->dynamicCall("Close()");
excel->dynamicCall("Quit()");
这是关闭 Excel 应用。
除此之外,还有很多类似的方法。
设置和获取属性
一般通过 setProperty() 方法设置属性,比如:
range->setProperty("VerticalAlignment", -4108);
range->setProperty("HorizontalAlignment", -4108);
range->setProperty("WrapText", true);
range->setProperty("MergeCells", true);
range->setProperty("Bold", isBold);
分别为设置单元格:
- 竖直居中。
- 水平居中。
- 文本自动换行。
- 单元格合并。
- 字体加粗。
而如果想获取属性就可以通过 property() 方法,会返回一个 QVariant 对象,可以根据需求通过 toString()、toInt() 等方法转为 Qt 的基本类型。
更多相关
除了上面提到的,更多的方法可以直接到微软官网查看文档。
简单封装代码
头文件 excelmanager.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
实现文件 excelmanager.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;
}
}
其中现有的功能主要是:
new_excel():按照给定目录创建新表格文件。open_excel():按照给定目录打开表格文件。get_cell_value():获取指定工作表中某行某列的单元格值(返回类型为QString)。set_cell_value():设置指定工作表中某行某列的单元格值(设置类型为QString)。save_excel()和save_excel_as():保存文件以及保存为路径。close()和free_excel():关闭文件和Application。- 以及一些基本的单元格样式设置,更多功能待补充。
其他
CoInitializeEx(nullptr, COINIT_MULTITHREADED);
需要在使用 COM 接口前使用此函数初始化。
程序中使用了静态成员,是希望在有多个工作表被操纵的时候,保证后台只有一个 Excel 应用在运行。
当然为了实现这一目标,程序也需要保证在使用 ExcelManger 时每个对象能够得到正确的析构。



No Comments