使用MFC操作EXCEL文件
分类: EXCEL 2012-09-03 09:30 14914人阅读 评论(5) 收藏 举报
excelmfcbooks工作applicationoffice
一、加载
1、 在VC6.0里创建一个MFC工程
2、打开MFCClassWizard窗口(查看—>建立类向导),选择Automation,单击AddClass按钮,选择Froma type library…,弹出文件选择对话框,之后定位到C:\Program Files\MicrosoftOffice\OFFICE11\EXCEL.EXE,在生成类中添加所有的对象(其实添加需要的即可,为了简便,不出错保留了冗余),如下图。
3、返回编辑器,查看工程文件,可发现多了EXCEL.9H及EXCEL9.CPP两个文件,拷贝出来,放在VS2005需要使用excel的工程文件中。
4. 打开stdafx.h头文件确保包含如下头文件:
if(!AfxOleInit() )
{
AfxMessageBox("初始化Ole出错!");
return FALSE;
}
为保证编译时不产生重复定义错误(可以验证一下是否成功加载,没有也能正常执行),我编译时出现了很多“类重复定义”异常,打开excel.h文件,在文件开始位置加入如下代码:
相应的,在文件末尾加入:
成功
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
一定数量的单元格,可对单元格进行单个或多个单元格进行操作。
在MSDN中,很少有excel方面的资料,但是在http://msdn.microsoft.com/zh-cn/ms348103.aspx中可以找到C#控制EXCEL方面的说明
二、操作EXCEL文件
1. 新建一个excel表,并填充两个单元格的实例
void CTestExcelDlg::OnButton1()
{
//Workbooks—>Workbook —>Worksheets—>Worksheet —>Range
_Application app; //Excel应用程序接口
Workbooks books; //工作薄集合
_Workbook book; //工作薄
Worksheets sheets; //工作表集合
_Worksheet sheet; //工作表
Range range; //Excel中针对单元格的操作都应先获取其对应的Range对象
Font font;
Range cols;
/*
COleVariant类为VARIANT数据类型的包装,在自动化程序中,通常都使用
VARIANT数据类型进行参数传递。故下列程序中,函数参数都是通过COleVariant
类来转换了的。
*/
//covOptional 可选参数的VARIANT类型
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
if( !app.CreateDispatch("Excel.Application") ){
this->MessageBox("无法创建Excel应用!");
return;
}
//获取工作薄集合
books=app.GetWorkbooks();
//添加一个工作薄
book=books.Add(covOptional);
//获取工作表集合
sheets=book.GetSheets();
//获取第一个工作表
sheet=sheets.GetItem(COleVariant((short)1));
//选择工作表中A1:A1单元格区域
range=sheet.GetRange(COleVariant("A1"),COleVariant("A1"));
//设置A1=HELLO EXCEL!"
range.SetValue(COleVariant("HELLO EXCEL!"));
//调整格式,设置粗体
font=range.GetFont();
font.SetBold(COleVariant((short)TRUE));
//选择A2单元格,插入一个公式"=RAND()*100000",并设置A2数字格式为货币形
式
range=sheet.GetRange(COleVariant("A2"),COleVariant("A2"));
range.SetFormula(COleVariant("=RAND()*100000"));
range.SetNumberFormat(COleVariant("$0.00"));
//选择A:A列,设置宽度为自动适应
cols=range.GetEntireColumn();
cols.AutoFit();
//显示Excel表格,并设置状态为用户可控制
app.SetVisible(TRUE);
app.SetUserControl(TRUE);
2. 打开一个已有的excel表格实例
[cpp] view plaincopy
CString strPath;
strPath += "C:\\template.xlt"; // 模板的路径
CFileFind filefind;
if( !filefind.FindFile( strPath ) )
{
AfxMessageBox( "没有找到模版文档,请其查找" );
return;
}
LPDISPATCH lpDisp; //接口指针
books=app.GetWorkbooks();
lpDisp = books.Open(m_filepath,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional
); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
book.AttachDispatch(lpDisp);
3. 保存一个excel文件实例
[cpp] view plaincopy
book.SetSaved(TRUE);
4. 另存一个excel文件实例
[cpp] view plaincopy
book.SaveAs(COleVariant(m_filename),covOptional,
covOptional,covOptional,
covOptional,covOptional,(long)0,
covOptional,covOptional,covOptional,
covOptional,covOptional); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
5. 释放一个excel文件实例
经试验证实,不释放第二次使用excel时会中断,放在类的析构里面有时调用不到,主动调用最保险。(有没有AttachDispatch()过都要释放,否则报错)
[cpp] view plaincopy
//释放对象(相当重要!)
Rang.ReleaseDispatch();
sheet.ReleaseDispatch();
sheets.ReleaseDispatch();
book.ReleaseDispatch();
books.ReleaseDispatch();
//退出程序
app.Quit();
//m_ExlApp一定要释放,否则程序结束后还会有一个Excel进程驻留在内存中,而且程序重复运行的时候会出错
app.ReleaseDispatch();
6. 修改一个excel单元格
[cpp] view plaincopy
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
range.SetValue2(COleVariant(value));
7. 取出一个excel单元格
实现Variant数据类型转换为CString类,这个只是一个示例,转换较为简单。
[cpp] view plaincopy
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
COleVariant rValue;
rValue=COleVariant(range.GetValue2());
rValue.ChangeType(VT_BSTR);
return CString(rValue.bstrVal);
8. 还有释放问题是最重要的问题:
首先变量必须全释放,无论当初是否绑定过;
其次,程序释放和程序关闭的顺序必须是
[cpp] view plaincopy
app.Quit();
app.ReleaseDispatch();
如果顺如颠倒如下:
app.ReleaseDispatch();
app.Quit();
出现的后果是程序关闭后,excel进程仍然运行,所以无法正常打开程序曾经打开excel表格。
附录(操作类源码):
[cpp] view plaincopy
#include "../Stdafx.h"
#include "OptExcel.h"
#include "excel.h"
#include "comdef.h"
_Application app;
Workbooks books;
_Workbook book;
Worksheets sheets;
_Worksheet sheet;
Range range;
Range cell;
Font font;
COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
////////////////////////////////////////////////////////////////////////
///Function: COptExcel
///Description: 初始化函数,初始化中附加excel应用程序
///Call: app.CreateDispatch(_T("Excel.Application")
////////////////////////////////////////////////////////////////////////
COptExcel::COptExcel(void)
{
if (::CoInitialize( NULL ) == E_INVALIDARG)
{
AfxMessageBox(_T("初始化Com失败!"));
return;
}
//验证office文件是否可以正确运行
if( !app.CreateDispatch(_T("Excel.Application")) )
{
AfxMessageBox(_T("无法创建Excel应用!"));
return;
}
//在程序执行文件路径名中,剪掉执行文件名,得到程序路径,追加模板文件名,得到模板完整路径
}
////////////////////////////////////////////////////////////////////////
///Function: ~COptExcel
///Description: 析构函数,释放对象,非常重要,不全部释放,占用内存,下
/// 一次使用此类时会中断
///Call: ReleaseDispatch()
////////////////////////////////////////////////////////////////////////
COptExcel::~COptExcel(void)
{
books.ReleaseDispatch();
book.ReleaseDispatch();
sheets.ReleaseDispatch();
sheet.ReleaseDispatch();
range.ReleaseDispatch();
font.ReleaseDispatch();
cell.ReleaseDispatch();
app.Quit();
app.ReleaseDispatch();
::CoUninitialize();
}
////////////////////////////////////////////////////////////////////////
///Function: OpenExcelBook
///Description: 打开表名为filename的文件,注意,文件路径非自动生成,以后
/// 考虑从下处理方法
///Call: GetAppPath()
///Input: CString filename 文件名
////////////////////////////////////////////////////////////////////////
bool COptExcel::OpenExcelBook(CString filename)
{
CFileFind filefind;
if( !filefind.FindFile(filename) )
{
AfxMessageBox(_T("文件不存在"));
return false;
}
LPDISPATCH lpDisp; //接口指针
books=app.GetWorkbooks();
lpDisp = books.Open(filename,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional, covOptional, covOptional,
covOptional, covOptional
); //与office 2000的不同,是个参数的,直接在后面加了两个covOptional成功了
book.AttachDispatch(lpDisp);
sheets=book.GetSheets();
sheet=sheets.GetItem(COleVariant((short)1)); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
return true;
}
void COptExcel::NewExcelBook()
{
books=app.GetWorkbooks();
book=books.Add(covOptional);
sheets=book.GetSheets();
sheet=sheets.GetItem(COleVariant((short)1)); //与的不同,是个参数的,直接在后面加了两个covOptional成功了
}
////////////////////////////////////////////////////////////////////////
///Function: OpenExcelApp
///Description: 打开应用程序(要注意以后如何识别用户要打开的是哪个文件)
////////////////////////////////////////////////////////////////////////
void COptExcel::OpenExcelApp(void)
{
app.SetVisible(TRUE);
app.SetUserControl(TRUE);
}
////////////////////////////////////////////////////////////////////////
///Function: SaveExcel
///Description: 用于打开数据文件,续存数据后直接保存
////////////////////////////////////////////////////////////////////////
void COptExcel::SaveExcel(void)
{
book.SetSaved(TRUE);
}
////////////////////////////////////////////////////////////////////////
///Function: SaveAsExcel
///Description: 保存excel文件
////////////////////////////////////////////////////////////////////////
void COptExcel::SaveAsExcel(CString filename)
{
book.SaveAs(COleVariant(filename),covOptional,
covOptional,covOptional,
covOptional,covOptional,(long)0,covOptional,covOptional,covOptional,
covOptional,covOptional);
}
////////////////////////////////////////////////////////////////////////
///Function: SetCellValue
///Description: 修改单元格内的值
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int row 单元格所在行
/// int col 单元格所在列
/// int Align 对齐方式默认为居中
////////////////////////////////////////////////////////////////////////
void COptExcel::SetCellValue(int row, int col,int Align)
{
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
range.SetValue2(COleVariant(value));
cell.AttachDispatch((range.GetItem (COleVariant(long(1)), COleVariant(long(1)))).pdispVal);
cell.SetHorizontalAlignment(COleVariant((short)Align));
}
////////////////////////////////////////////////////////////////////////
///Function: GetCellValue
///Description: 得到的单元格中的值
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int row 单元格所在行
/// int col 单元格所在列
///Return: CString 单元格中的值
////////////////////////////////////////////////////////////////////////
CString COptExcel::GetCellValue(int row, int col)
{
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
COleVariant rValue;
rValue=COleVariant(range.GetValue2());
rValue.ChangeType(VT_BSTR);
return CString(rValue.bstrVal);
}
////////////////////////////////////////////////////////////////////////
///Function: SetRowHeight
///Description: 设置行高
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int row 单元格所在行
////////////////////////////////////////////////////////////////////////
void COptExcel::SetRowHeight(int row, CString height)
{
int col = 1;
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
range.SetRowHeight(COleVariant(height));
}
////////////////////////////////////////////////////////////////////////
///Function: SetColumnWidth
///Description: 设置列宽
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int col 要设置列宽的列
/// CString 宽值
////////////////////////////////////////////////////////////////////////
void COptExcel::SetColumnWidth(int col,CString width)
{
int row = 1;
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
range.SetColumnWidth(COleVariant(width));
}
////////////////////////////////////////////////////////////////////////
///Function: SetRowHeight
///Description: 设置行高
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int row 单元格所在行
////////////////////////////////////////////////////////////////////////
CString COptExcel::GetColumnWidth(int col)
{
int row = 1;
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
VARIANT width = range.GetColumnWidth();
CString strwidth;
strwidth.Format(CString((LPCSTR)(_bstr_t)(_variant_t)width));
return strwidth;
}
////////////////////////////////////////////////////////////////////////
///Function: GetRowHeight
///Description: 设置行高
///Call: IndexToString() 从(x,y)坐标形式转化为“A1”格式字符串
///Input: int row 要设置行高的行
/// CString 宽值
////////////////////////////////////////////////////////////////////////
CString COptExcel::GetRowHeight(int row)
{
int col = 1;
range=sheet.GetRange(COleVariant(IndexToString(row,col)),COleVariant(IndexToString(row,col)));
VARIANT height = range.GetRowHeight();
CString strheight;
strheight.Format(CString((LPCSTR)(_bstr_t)(_variant_t)height));
return strheight;
}
////////////////////////////////////////////////////////////////////////
///Function: IndexToString
///Description: 得到的单元格在EXCEL中的定位名称字符串
///Input: int row 单元格所在行
/// int col 单元格所在列
///Return: CString 单元格在EXCEL中的定位名称字符串
////////////////////////////////////////////////////////////////////////
CString COptExcel::IndexToString( int row, int col )
{
CString strResult;
if( col > 26 )
{
strResult.Format(_T("%c%c%d"),'A' + (col-1)/26-1,'A' + (col-1)%26,row);
}
else
{
strResult.Format(_T("%c%d"), 'A' + (col-1)%26,row);
}
return strResult;
}
////////////////////////////////////////////////////////////////////////
///Function: LastLineIndex
///Description: 得到表格总第一个空行的索引
///Return: int 空行的索引号
////////////////////////////////////////////////////////////////////////
int COptExcel::LastLineIndex()
{
int i,j,flag=0;
CString str;
for(i=1;;i++)
{
flag = 0;
//粗略统计,认为前列都没有数据即为空行
for(j=1;j<=5;j++)
{
str.Format(_T("%s"),this->GetCellValue(i,j).Trim());
if(str.Compare(_T(""))!=0)
{
flag = 1;
break;
}
}
if(flag==0)
return i;
}
}