Qt 实践——如何用 Qt 操作 Excel
Contents
原理
用到的库和类
一般 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