C++操作Excel学习笔记

一:

【当前博文转载自http://blog.csdn.net/fullsail/article/details/4067416

C++读取Excel文件方式比较

C++读取Excel的XLS文件的方法有很多,但是也许就是因为方法太多,大家在选择的时候会很疑惑。

由于前两天要做导表工具,比较了常用的方法,总结一下写个短文,

 

1.OLE的方式

这个大约是最常用的方式,这个方式其实启动了一个EXCEL的进程在背后读写EXCEL文件,这个方式的最大好处是什么事情都能做。包括设置EXCEL的格式,增加删除Sheet,读写单元格,等等。功能几乎是最全的,而且使用起来也不是特别的难。

其基本方法都是使用导出的.h文件进行OLE操作,但是由于OLE的接口说明文档不多,想非常完美的使用她们也不是太容易,好在例子也很多。

网上普遍认为OLE速度慢,EXCEL的OLE读写方式也基本一样。但是读取速度可以改进,如果在读取的加载整个Sheet的Range的全部数据,而不是一个个单元格读取,那么速度还是相对不错。想想原理也很简单,整体读取减少了OLE的交互次数。OLE的写入方式一般只能几个进行比较方便,所以速度可能要快很多。

我自己的亲身体会是,一个EXCEL文件,100多列的字段,如果采用一个个单元格的读取方式,1s大约3条左右的记录,如果整体读取,速度可以提高几十倍。

OLE读写EXCEL方式功能很强大,读取速度还可以,但写入速度不高,当然这个方式不可能移植的,而且你必须安装了EXCEL。

 

2.Basic EXCEL 方式

这是CodeProject上的一个推荐开源工程了,

http://www.codeproject.com/KB/office/BasicExcel.aspx

作者是基于EXCEL的文件格式进行的处理。但是为什么叫Basic EXCEL呢。

他不支持很多东西,公式,文件格式,表格合并等(有人说中文支持也不好),所以可以认为他只支持最基本的EXCEL表格,

我自己的尝试是如果这个EXCEL文件有其他元素(公式,格式等),使用Basic EXCEL读取会失败。

OLE读写EXCEL方式功能比较弱,由于是直接根据文件格式操作,读写速度都不错,你也不需要按照EXCEL,另外这个方式是可以移植的,但是有一些成本,其代码比较晦涩难懂,而且没有注释,另外即使在Windows平台上,告警也很多。

 

3.Sourceforge 上的几个EXCEL库。

Sourceforge 上有几个开源的的EXCEL库,但是完善的不多,有的是为了PHP读写EXCEL准备的,包括libXLS,XLSlib,SmartEXCEL等。我下载了几个实验了一下,在Widonws都没有编译成功。也罢了。

 

4.ODBC的方式

这个亲身没有尝试过,但是按照原理,应该只能读写。

速度吗,ODBC的速度本来就是出名的慢了。

http://www.vckbase.com/document/viewdoc/?id=421

 

值得一提的是Basic EXCEL的作者原来在CodeProject上有一个给予ODBC方式的封装CSpreadSheet 。如果有兴趣,大家可以去看看。其实内心还是很佩服这个作者的。

http://www.codeproject.com/KB/database/cspreadsheet.aspx

 

5.ADO的方式

ADO的方式听说应该就是使用OLEDB的方式。和OLE的方式应该没有本质区别。我看了看例子也和OLE很像

  

6.LibXL

LibXL 是一个收费的EXCEL的库。

http://www.libxl.com/

按照他的说明,他可以不依赖EXCEL读取XLS文件。包括设置格式等。看例子操作应该很简单。但是是否可以移植到Linux平台,我估计难度也不小。呵呵。

由于要收费,没有法子测试了。

 

7.网上一些号称不用OLE读取EXCEL例子

初步看了一下,这个应该是网上探索EXCEL格式文档的例子。可以实际操作的方式不强。

 

二:

【当前博文转载自http://www.byywee.com/page/M0/S599/599654.html

VS2010 C++ 操纵Excel表格的编程实现

经由过程VC实现对Excel表格的操纵的办法有多种,如:经由过程ODBC数据库实现,经由过程解析Excel表格文件,经由过程OLE/COM的实现。本文首要研究经由过程OLE/COM实现对Excel表格的操纵。

 

本文源码的应用景象申明:

Windows XP SP3

Microsoft Visual Studio 2010

Microsoft Office Excel 2007

 

1、添加OLE/COM支撑。

起首,应用法度必须添加对OLE/COM的支撑,才干导入OLE/COM组件。

本文应用的是MFC对话框法度,在创建工程的领导中选中Automation选项即可为法度主动添加响应的头文件和OLE库初始化代码。

经由过程查看源代码,可以知道在stdafx.h的头文件中,添加了OLE/COM很多类所需添加的头文件。

#include         // MFC 主动化类

同时,在应用法度类的InitInstance函数中,添加了OLE/COM的初始化代码,如下所示:

// 初始化 OLE 库

if (!AfxOleInit())

{

 

AfxMessageBox(IDP_OLE_INIT_FAILED); 

return FALSE; 

}
 

2、导入并封装Excel中的接口

Excel作为OLE/COM库插件,定义好了各类交互的接口,这些接口是跨说话的接口。VC可以经由过程导入这些接口,并经由过程接口来对Excel的操纵。

因为本文只关怀对Excel表格中的数据的读取,首要存眷几个_ApplicationWorkbooks_WorkbookWorksheets_WorksheetRange等几个接口。Excel的各类接口的属性、办法可以经由过程MSDNOffice Development进行查询。

VS2010导入OLE/COM组件的接口的步调为:Project->Class Wizard->Add Class->MFC Class From TypeLib,先选择要导入的组件地点的路径,即Excel.exe地点的路径,然后再选择要导入的Excel类型库中的接口。

在完成接口导入后,VS2010将主动为导入的接口创建响应的实现类,用于对接口属性和办法的实现。因为标准的C++没有属性接见器,只能添加一个两个存取函数来实现对属性的接见,经由过程在属性名称前加上get_put_前缀分别实现对属性的读写操纵。即,由VC主动完成C++类对接口的封装。

文所导入的接口对应的类和头文件的申明如下所示:

 Excel接口 导入类  头文件  申明
_Application

CApplicaton

Application.h

Excel应用法度。

Workbooks CWorkbooks Workbooks.h 工作簿的容器,里面包含了Excel应用法度打开的所有工作簿
_Workbook CWorkbook

Workbook.h

单个工作簿。
Worksheets CWorksheets Worksheets.h

单个工作簿中的Sheet表格的容器,包含该工作簿中的所有Sheet。

_Worksheet CWorksheet Worksheet.h 单个Sheet表格。
Range CRange Range.h 必然命量的单位格,可对单位格进行单个或多个单位格进行操纵

 

3、导入Excel的全部类型库

接口对应类只是对接口的属性和办法进行了封装,而Excel中的数据类型,如列举类型却并为并不克不及应用,是,为了更便利的操纵Excel,还须要导入Excel的数据类型。 

经由过程查看导入接口对应的头文件可以发明,在所有导入接口的头文件中,都邑有这么行:

#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace

这行代码的感化是导入Excel全部类型库到工程中。

VS2010主动产生的导入代码存在以下几个题目:

1)若是导入了多个接口,每个头文件都邑把类型库导入一次,若是引用多个头文件,会导致类型库反复导入。

2Excel类型库中有些类型会跟MFC类库的某些类型冲突。

3Excel类型库的某些类型跟其他OfficeVB的某些库相干,若是不导入相干库,将导致这些类型无法应用。。

以上三点题目的解决办法如下:

1)仅在_Application接口对应头文件中导入Excel类型库。

2)对冲突的类型进行重定名。

3)在导入Excel类型库之前,先导入OfficeVB的相干库。

更改后的导入类型库的代码如下:

 

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE12\\MSO.DLL" \ 

rename("RGB", "MSORGB") \ 

rename("DocumentProperties", "MSODocumentProperties") 

using namespace Office; 

 

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB" 

using namespace VBIDE; 

 

#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" \ 

rename("DialogBox", "ExcelDialogBox") \ 

rename("RGB", "ExcelRGB") \ 

rename("CopyFile", "ExcelCopyFile") \ 

rename("ReplaceText", "ExcelReplaceText") \

no_auto_exclude 

Using namesapce Excel;

 

编译法度后,会在DebugRelease目次下生成三个文件mso.tlhvbe6ext.tlhexcel.tlh。经由过程打开文件可知,该三个文件的定名空间分别是OfficeVBIDEExcel。导入了Excel的全部类型库后,就可以应用Excel中的所有类型了。
 

4、操纵Excel步调 

操纵Excel的首要步调如下: 

1)创建一个Excel应用法度。 

2)获得Workbook的容器。 

3)打开一个Workbook或者创建一个Workbook 

4)获得Workbook中的Worksheet的容器。 

5)打开一个Worksheet或者创建一个WorkSheet 

6)经由过程RangeWorkSheet中的单位格进行读写操纵。 

7)保存Excel 

8)开释资料。
 

5、批量处理惩罚Excel表格 

VC经由过程OLE/COM操纵Excel,是经由过程过程间的组件技巧。是以,每次读写Excel中的单位格时,都要进行过程间的切换。当数据量大,若是一个单位格一个单位格的读取,首要的时候都花费在过程切换中。是以读取多个单位格,将可有效的进步法度的运行效力。 

对多个单位格的读写操纵可以经由过程CRange中以下两个成员函数来完成。 

VARIANT get_Value2(); 

void put_Value2(VARIANT& newValue); 

此中,输入参数newValue只要输入一个二维数组,即可实现向Excel中一次写入多个单位格的值。 

此中,VARIANT中实现二维数据的办法可参考 

http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html 

当然,在对CRange类进行操纵之前,要设置CRange类对应的单位格。
 

6Excel表格的保存 

1)若是要保存打开的工作簿,应用CWorkbook类的Save函数就可以保存工作簿,原文件将被覆盖。 

2)若是是新创建的工作簿,或者是要另存为,可应用CWorkbook类的SaveAs函数。

 

SaveAs的参数斗劲多。此中,第1个参数是设置要保存文件的路径;第2个参数是设置文件的格局,可在MSDN中查看列举类型XlFileFormat来懂得Excel的文件格局。经过测试,在本文所用的测试景象中,Excel2003的文件格局是xlExcel8Excel2007的文件格局是xlExcel4
 

7、获取当前Excel的版本 

可以经由过程CApplicationget_Version函数来获得Excel的版本,此中,Excel2007的主版本号是12Excel2003的主版本号是11
 

8、示例源代码 

首要代码如下: 

C++操作Excel学习笔记(二)C++操作Excel学习笔记(二)View Code

m_ListCtrl.SetExtendedStyle(LVS_REPORT | LVS_EX_FULLROWSELECT);

CApplication ExcelApp;
CWorkbooks books;
CWorkbook book;
CWorksheets sheets;
CWorksheet sheet;
CRange range;
LPDISPATCH lpDisp = NULL;

//创建Excel 办事器(启动Excel)
if(!ExcelApp.CreateDispatch(_T("Excel.Application"),NULL))
{
AfxMessageBox(_T("启动Excel办事器失败!"));
return -1;
}


CString strExcelVersion = ExcelApp.get_Version();
int iStart = 0;
strExcelVersion = strExcelVersion.Tokenize(_T("."), iStart);
if (_T("11") == strExcelVersion)
{
AfxMessageBox(_T("当前Excel的版本是2003。"));
}
else if (_T("12") == strExcelVersion)
{
AfxMessageBox(_T("当前Excel的版本是2007。"));
}
else
{
AfxMessageBox(_T("当前Excel的版本是其他版本。"));
}

ExcelApp.put_Visible(TRUE);
ExcelApp.put_UserControl(FALSE);


books.AttachDispatch(ExcelApp.get_Workbooks());


CString strBookPath = _T("C:\\tmp.xls");
try
{

lpDisp = books.Open(strBookPath, 
vtMissing, vtMissing, vtMissing, vtMissing, vtMissing,
vtMissing, vtMissing, vtMissing, vtMissing, vtMissing, 
vtMissing, vtMissing, vtMissing, vtMissing);
book.AttachDispatch(lpDisp);
}
catch(...)
{

lpDisp = books.Add(vtMissing);
book.AttachDispatch(lpDisp);
}



sheets.AttachDispatch(book.get_Sheets());


CString strSheetName = _T("NewSheet");
try
{

lpDisp = sheets.get_Item(_variant_t(strSheetName));
sheet.AttachDispatch(lpDisp);
}
catch(...)
{

lpDisp = sheets.Add(vtMissing, vtMissing, _variant_t((long1), vtMissing);
sheet.AttachDispatch(lpDisp);
sheet.put_Name(strSheetName);
}

system("pause");


lpDisp = sheet.get_Range(_variant_t("A1"), _variant_t("J10"));
range.AttachDispatch(lpDisp);

VARTYPE vt = VT_I4; 
SAFEARRAYBOUND sabWrite[2]; 
sabWrite[0].cElements = 10;
sabWrite[0].lLbound = 0;
sabWrite[1].cElements = 10;
sabWrite[1].lLbound = 0;

COleSafeArray olesaWrite;
olesaWrite.Create(vt, sizeof(sabWrite)/sizeof(SAFEARRAYBOUND), sabWrite);


long (*pArray)[2] = NULL;
olesaWrite.AccessData((void **)&pArray);
memset(pArray, 0, sabWrite[0].cElements * sabWrite[1].cElements * sizeoflong));


olesaWrite.UnaccessData();
pArray = NULL;


long index[2] = {0, 0};
long lFirstLBound = 0;
long lFirstUBound = 0;
long lSecondLBound = 0;
long lSecondUBound = 0;
olesaWrite.GetLBound(1, &lFirstLBound);
olesaWrite.GetUBound(1, &lFirstUBound);
olesaWrite.GetLBound(2, &lSecondLBound);
olesaWrite.GetUBound(2, &lSecondUBound);
for (long i = lFirstLBound; i <= lFirstUBound; i++)
{
index[0] = i;
for (long j = lSecondLBound; j <= lSecondUBound; j++)
{
index[1] = j;
long lElement = i * sabWrite[1].cElements + j; 
olesaWrite.PutElement(index, &lElement);
}
}


VARIANT varWrite = (VARIANT)olesaWrite;
range.put_Value2(varWrite);

system("pause");


CString strSaveAsName = _T("C:\\new.xlsx");
CString strSuffix = strSaveAsName.Mid(strSaveAsName.ReverseFind(_T(""."")));
XlFileFormat NewFileFormat = xlOpenXMLWorkbook;
if (0 == strSuffix.CompareNoCase(_T(".xls")))
{
NewFileFormat = xlExcel8;
}
book.SaveAs(_variant_t(strSaveAsName), _variant_t((long)NewFileFormat), vtMissing, vtMissing, vtMissing, 
vtMissing, 0, vtMissing, vtMissing, vtMissing, 
vtMissing, vtMissing);

system("pause");


VARIANT varRead = range.get_Value2();
COleSafeArray olesaRead(varRead);

VARIANT varItem;
CString strItem;
lFirstLBound = 0;
lFirstUBound = 0;
lSecondLBound = 0;
lSecondUBound = 0;
olesaRead.GetLBound(1, &lFirstLBound);
olesaRead.GetUBound(1, &lFirstUBound);
olesaRead.GetLBound(2, &lSecondLBound);
olesaRead.GetUBound(2, &lSecondUBound);
memset(index, 0, 2 * sizeoflong));
m_ListCtrl.InsertColumn(0, _T(""), 0, 100);
for (long j = lSecondLBound; j<= lSecondUBound; j++)
{
CString strColName = _T("");
strColName.Format(_T("%d"), j);
m_ListCtrl.InsertColumn(j, strColName, 0, 100);
}
for (long i = lFirstLBound; i <= lFirstUBound; i++)
{
CString strRowName = _T("");
strRowName.Format(_T("%d"), i);
m_ListCtrl.InsertItem(i-1, strRowName);

index[0] = i;
for (long j = lSecondLBound; j <= lSecondUBound; j++)
{
index[1] = j;
olesaRead.GetElement(index, &varItem);

switch (varItem.vt)
{
case VT_R8:
{
strItem.Format(_T("%d"), (int)varItem.dblVal);
}

case VT_BSTR:
{
strItem = varItem.bstrVal;
}

case VT_I4:
{
strItem.Format(_T("%ld"), (int)varItem.lVal);
}

default:
{

}
}

m_ListCtrl.SetItemText(i-1, j, strItem);
}
}




sheet.ReleaseDispatch();
sheets.ReleaseDispatch();
book.ReleaseDispatch();
books.ReleaseDispatch();
ExcelApp.Quit();
ExcelApp.ReleaseDispatch();
 

示例源代码的工程文件的下载链接如下:

https://files.cnblogs.com/xianyunhe/ReadWriteExcel.rar
 

参考材料 

1http://www.cnblogs.com/xianyunhe/archive/2011/09/13/2174703.html

2http://hfp0601.blog.163.com/blog/static/228483522011031104718762/ 

3http://www.cppblog.com/sleepwom/archive/2009/10/03/97804.html 

4http://www.rondebruin.nl/saveas.html

 

 

三:

由于学习对Excel的操作是临时学的,有很多东西只是一知半解,但好歹是能运行了,相关内容可以参照前两篇学习笔记。

本文中使用的是OLE方式读写,环境是VS2008和Office2003。现在的编译器有自动完成功能,很容易找到相应的成员函数。查看函数原型有助于理解参数的意义,但仍是有些参数也搞不明白是什么作用,或者如何设置。Excel相关的预定义枚举类型,都是Xl开头,比如XlHAlign,是水平对齐,可以用XlHAlign::找到居中、靠右、靠左等应该设置的值。

步骤如下:

1.新建MFC工程,Project - Add Class - MFC Class From TypeLib,选择File,在Office安装目录下找到EXCEL.EXE,选择相应的接口(参考学习笔记二)。

 

2.VS2008会在工程中加入相应的头文件。打开头文件,把#import "D:\\Program Files\\Microsoft Office\\Office12\\EXCEL.EXE" no_namespace 一行改成:

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\OFFICE11\\MSO.DLL" \
 rename("RGB", "MSORGB") \
 rename("DocumentProperties", "MSODocumentProperties") \
 rename("SearchPath","MsoSearchPath") \
 rename_namespace("Office")
using namespace Office;

#import "C:\\Program Files\\Common Files\\Microsoft Shared\\VBA\\VBA6\\VBE6EXT.OLB"

using namespace VBIDE;

#import "C:\\Program Files\\Microsoft Office\\Office11\\EXCEL.EXE" \
 rename("DialogBox", "ExcelDialogBox") \
 rename("RGB","ExcelRGB") \
 rename("CopyFile", "ExcelCopyFile") \
 rename("ReplaceText", "ExcelReplaceText") \
 no_auto_exclude

using namespace Excel;
#undef ExitWindows
#undef DialogBox
#undef RGB

注意“\”字符后面不能放空格

 

3.由于许多Word的对象与Excel对象的名字是相同的,因此两者同时使用是,必须使用名字空间将其区分。方法简单,比如自定义名字空间是_excel,则把接口头文件中

class C***

{...};

改成

namespace _excel

{

class C***

{...};

};

 

4.完成,现在可以编程了。

 

下面是个简单的例子,包括合并单元格、设置单元格内容、设置单元格格式、设置边框、获取单元格内容、保存工作簿等功能

头文件部分

#include // 为了方便操作 VARIANT 类型变量,使用 CComVariant 模板类

#include "CApplication.h"
#include "CBorders.h"
#include "CFont0.h"
#include "Cnterior.h"
#include "CRange.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"

 

实现部分

void CMyExcelDlg::OnBnClickedOk()
{
 _excel::CApplication app;
 _excel::CBorders borders;
 _excel::CFont0 font;
 _excel::Cnterior interior;//背景色
 _excel::CRange range;
 _excel::CWorkbook workbook;
 _excel::CWorkbooks workbooks;
 _excel::CWorksheet worksheet;
 _excel::CWorksheets worksheets;
 CoInitialize(NULL);//初始化COM,最后还有CoUninitialize
 COleVariant covOptional((long)DISP_E_PARAMNOTFOUND,VT_ERROR);

 if(!app.CreateDispatch(_T("EXCEL.application"))) //启动WORD
 {
  AfxMessageBox(_T("居然你连OFFICE都没有安装吗?"));
  return;
 }
 app.put_Visible(TRUE);//设置表可见性
 app.put_DisplayFullScreen(FALSE);//设置全屏显示
 app.put_DisplayAlerts(FALSE);//屏蔽警告
 
 //打开工作簿
 CString strPath;
 strPath = "C:\\Documents and Settings\\Administrator\\桌面\\MyExcel\\excel.xls";
 workbooks = app.get_Workbooks();
 try
 {
  workbook = workbooks.Add(_variant_t(strPath));
 }
 catch (CException* e)
 {
  workbook = workbooks.Add(vtMissing);//找不到就新建一个
 }
 

 //获取工作表worksheet(三种方法)
 worksheet = workbook.get_ActiveSheet();
 worksheets = workbook.get_Sheets();
 //worksheet = worksheets.get_Item((_variant_t("sheet2")));
 //worksheet = worksheets.get_Item((_variant_t(1)));

 

 //新建工作表(此方法错,可能是参数问题)

 worksheets.Add(vtMissing,vtMissing,_variant_t((long)1),_variant_t(XlSheetType::xlWorksheet));//第三个参数是新表的数量

  //获取区域

 range = worksheet.get_Range(_variant_t("A1"), _variant_t("A3"));
 //合并单元格
 range.Merge(_variant_t((long)0));

 

 //设置单元格内容
 range = worksheet.get_Range(_variant_t("B2"), _variant_t("C5"));
 range.put_Value2(_variant_t("hey"));//参数是二维数组可以批量设置单元格值

 

 //设置单元格格式
 range = worksheet.get_Range(_variant_t("F2"), _variant_t("G5"));
 range.put_HorizontalAlignment(_variant_t(XlHAlign::xlHAlignRight));//水平对齐
 range.put_VerticalAlignment(_variant_t(XlVAlign::xlVAlignBottom));//竖直对齐
 range.put_ColumnWidth(_variant_t(35));//单位不明

 range.put_RowHeight(_variant_t(24));//磅
 font = range.get_Font();//字体
 font.put_Italic(_variant_t(1));//斜体
 interior =range.get_Interior();//底色
 interior.put_Color(_variant_t(76));

 

//获取单元格内容
 CString getdata;//定义字符串变量
 _variant_t rValue;
 range = worksheet.get_Range(_variant_t("A1"),_variant_t("A1"));
 rValue = range.get_Value2();
 getdata = rValue.bstrVal;

 

//线框,border会对range中所有单元格都做设置,
 range = worksheet.get_Range(_variant_t("A5"), _variant_t("C9"));
 borders = range.get_Borders();
 borders.put_LineStyle(_variant_t(XlLineStyle::xlDouble));
 
 range = worksheet.get_Range(_variant_t("A12"), _variant_t("C13"));
 range.BorderAround(_variant_t(XlLineStyle::xlDashDot), 2, 8, vtMissing);//外框线

 

//另存为
 covOptional = COleVariant((long)DISP_E_PARAMNOTFOUND,VT_ERROR);
 COleVariant varZero((short)0); 
 COleVariant varTrue(short(1),VT_BOOL); 
 COleVariant varFalse(short(0),VT_BOOL);

 workbook.SaveAs(COleVariant(strPath), COleVariant((long)XlFileFormat::xlWorkbookNormal), vtMissing, vtMissing,
  vtMissing, vtMissing, (long)0, vtMissing,
  vtMissing, vtMissing, vtMissing, vtMissing);
 //workbook.Save();
 
 AfxMessageBox(_T(""));

//所有东西都需要ReleaseDispatch,否则会报错
 borders.ReleaseDispatch();

 font.ReleaseDispatch();
 interior.ReleaseDispatch();
 range.ReleaseDispatch();
 workbook.ReleaseDispatch();
 workbooks.ReleaseDispatch();
 worksheet.ReleaseDispatch();
 worksheets.ReleaseDispatch();
 app.Quit();//Excel退出
 app.ReleaseDispatch();
 CoUninitialize();//对应CoInitialize
 OnOK();
}

 

四:

【当前博文转载自 http://blog.csdn.net/sgdgoodboy/article/details/2102628】
【本文前半部分与word相关,发在C++操作Word学习笔记(三)

 EXCEL篇及命名空间说明

1 Excel组件对象模型    
Microsoft Office Excel 2003文档中的数据是高度结构化的,因此Excel对象模型也具有层次结构并且简单明了。Excel 提供了数百个您可能需要与之交互的对象,但是最为重要的是以下四个对象:Application 对象、Workbook 对象、Worksheet 对象和Range 对象。很多工作都是围绕这四个对象进行的。
Application 对象。Application 对象表示 Excel 应用程序本身。Application 对象提供了大量有关正在运行的应用程序、应用于该实例的选项以及在该实例中打开的当前用户的对象的信息。
Workbook 对象。Workbook 类表示 Excel 应用程序内的单个工作簿。Application 类的许多成员同时也是 Workbook 类的成员。在这种情况下,属性应用于特定的工作簿(而非应用于活动工作簿)。
Worksheet 对象。虽然 Worksheet 类提供了大量成员,但大部分属性、方法和事件都与 Application 和/或 Workbook 类提供的成员相同或相似。Excel 提供 Sheets 集合作为 Workbook 对象的属性,但 Excel 中没有 Sheet 类。实际上,Sheets 集合的每个成员不是 Worksheet 对象就是 Chart 对象。
Range 对象。Range 对象是 Excel 应用程序中最常用的对象。在能够处理 Excel 内的任何范围之前,必须将它表示为 Range 对象,并处理该对象的方法和属性。Range 对象表示一个单元格、一行、一列、包含一个或多个单元格块(可以连续,也可以不连续)的单元格选定范围,甚至多个工作表中的一组单元格。
对于Microsoft Office Excel 2003,通常可以在..\\Microsoft Office\\OFFICE11\\ EXCEL.exe获得相关接口类。常用的有_Application, Workbooks, _Workbook, Worksheets, _Worksheet, Range,以及用于生成图表的_Chart等。

另外,使用MS Graph对象的技术同样可以生成数据图表。但是,对象写入大数据量非常缓慢的。MS Graph工作原理是每写入一个数据就要对图表进行更新,因此,MS Graph对于小数据制作图表是合适的(实现代码比EXCEL要少),但对于大数据这种工作原理是难以忍受的。尽管如此,EXCEL与MS Graph的接口函数却是非常相似的。

2 Excel启动与退出    
使用Application 对象,关联接口、释放接口。具体代码如下:
_Application theExcelApp;
theExcelApp.CreateDispatch("Excel.Application", NULL); //关联接口
////退出
theExcelApp.Quit();  ////退出
theExcelApp.ReleaseDispatch();  //释放接口

3 Excel打开记事本(*.txt)        
通常,我们需要从文本(*.txt)文件中载入数据。Excel的Workbooks对象提供了打开文本的函数OpenText ()。OpenText()函数声明如下:
OpenText(LPCTSTR Filename, const VARIANT& Origin, const VARIANT& StartRow, const VARIANT& DataType, long TextQualifier, const VARIANT& ConsecutiveDelimiter, const VARIANT& Tab, const VARIANT& Semicolon, const VARIANT& Comma, const VARIANT& Space, const VARIANT& Other, const VARIANT& OtherChar, const VARIANT& FieldInfo, const VARIANT& TextVisualLayout, const VARIANT& DecimalSeparator, const VARIANT& ThousandsSeparator, const VARIANT& TrailingMinusNumbers, const VARIANT& Local)
参数说明如下:
Filename 文本路径。
Origin 文件原始格式。通常值为936,表示简体中文。
StartRow 导入起始始行。在本报告中第一行为标题行,导入起始行为2。
DataType 数据类型。值设为1。
TextQualifier 文本格式。值为1。
ConsecutiveDelimiter 连续分隔符。值为TRUE
Tab Tab分隔符。值为FALSE。
Semicolon 分号分隔符。值为FALSE。
Comma 逗号分隔符。值为FALSE。
Space 空格分隔符。本电子报告中通常以空格作为分隔符,因此值为TRUE。如若采用其他分隔符,请适当修改。
Other 其它分隔符。值为FALSE。
OtherChar 其他文本识别符号。值为NULL。
FieldInfo 区域信息。同载入文本列数据格式相关。设为VarOpt。
TextVisualLayout 文本可见版式。设为VarOpt。
DecimalSeparator 小数分隔符。设为VarOpt。
ThousandsSeparator 千位分隔符。设为VarOpt。
TrailingMinusNumbers 按负号跟踪负数。设为TRUE。
Local 本地数据。设为VarOpt。
以上各参数请根据适当需要修改,并根据调试VBA宏代码获得参数值。
要说明的是,这种方法载入数据将从B列往后分布。即,如果是TXT文本里有两列数据,那么载入EXCEL后,这两列数据将分布在B列与C列,而A列为空。这个原因我也一直不得其解(不知道是我们合作方提供的TXT文本本身设置问题还是别的问题)。这点请读者注意,也请高手指点。

4 获取Excel行数目     
载入记事本数据后,需要调用_Worksheet对象获得数据的行数目。具体代码如下:
_Worksheet ::GetUsedRange();
获得已用区域,返回Range对象。注意,这里不能调用_Worksheet ::GetRange();
Range:: GetRows();
获得行对象。返回Range对象。
Range:: GetCount();
获得行数目。
获得行数目在进行生成图表是很重要的。在生成图表时,载入源数据的区域时需要获得行数目。

5 生成Excel图表及格式         
使用对象。以下要设置其格式。
_Chart:: SetChartType 设置图表类型。如果使用无数据点平滑线散点图,值为73。其它图表类型请自己录制VBA宏然后调试获得参数值。
_Chart:: SetSourceData生成图表的原数据。传递一个Range对象。
_Chart:: SetHasLegend 标注。设为FALSE,不显示标注。
_Chart:: SetHasTitle 标题。设为TRUE,显示标题。
并假设获得行数目为432,则SetSourceData的参数值为Range(“B1”, “C432”)。

如果需要对网格线进行格式控制,需要调用以下函数:
_Char::Axes 返回Axis对象
Axis::SetHasMajorGridlines 设置主格线,TRUE
Axis::SetHasMinorGridlines 设置次格线,FALSE
Axis::GetMajorGridlines 获得主格线对象(前提是设置主格线为TRUE),返回Gridlines对象
Gridlines::GetBorder 获得边框对象,返回Borders对象
Borders::SetColorIndex 设置颜色,57表示黑色
Borders::SetLineStyle 设置线条格式,-4118表示虚线
Borders::SetWeight 设置粗细
以上Borders各参数值可根据需要适当修改。

Axis::SetCrossesAt 可设置坐标轴相交位置。通常需要Axis::GetMinimumScale获得最小刻度值,然后相交于最小刻度值。

6 设置标题文字及曲线格式   
使用AxisTitle ,,Font对象设置文字,包括设置文字上标等。注意,Excel并不提供类似于Word的Selection对象,要进行文字格式控制,通常需要用到Characters对象,即对指定文字进行格式控制。
使用Series,Borders对象可对曲线进行控制。可利用_Char:: SeriesCollection返回一个Series对象。

7 保存    
使用_Workbook:: SaveAs函数。具体参数值设置较为简单,参看VBA宏代码即可。此处略。

8 命名空间namespace     
由于许多Word的对象与Excel对象的名字是相同的,因此,必须使用名字空间将其区分。命名空间的使用方法很简单,在.h和.cpp文件分别添加
namespace mynamespace
{
   //Statement;
}
把名字有冲突的类的声明与实现放入namespace的作用域里。然后调用类是前面加命名空间作用符。
举例如下:Word和Excel都有_Application对象,如果不使用命名空间则会发生编译错误。
可在excel.h添加
namespace myExcel
{
     class _Application : public COleDispatchDriver
{
   //Statement;
}
}
在excel.cpp将所有_Application的方法放入到命名空间中。
namespace myExcel
{
(_Application的方法实现代码)
}
调用Excel的_Application对象类时,使用方法为
myExcel:: _Application _myExcelApp;
即声明该_Application属于myExcel命名空间作用域。
关于命名空间在C++教材的“高级主题部分”会有涉及。

 
 

 

 

 

 

posted @ 2013-12-31 17:18  Zucc_zt  阅读(19886)  评论(0编辑  收藏  举报