【MFC/C++ 操作Excel】将数字格式单元格转为文本格式
序
首先,请您先阅读 MFC操作office通用分析方法一篇,或者你需要了解本文的分析方法是按如下进行的:
1. 将我们的处理过程用宏记录下来
2. 将这一过程从VB翻译为VC
正文
当我们在用MFC操作excel时,为了操作的方便性,常常需要将数据转为文本格式来保存,这一过程怎样用C++来实现呢?
第一步:我们可以使用以下方法将文本转为文本格式:选中要转为文本格式的单元格,右键-》设置单元格格式-》文本-》确定。
第二步:上面这一过程用宏记录下来是这样的,下面选择的是从A5到J64之间的单元格:
- Range("A5:J64").Select
- Selection.NumberFormatLocal = "@"
第三步:将上述VB转为VC实现:
//将beginS到endS之间的单元格转为文本格式存储
- BOOL SetTextFormat(CString beginS, CString endS)
- {
- //注意,这里的m_ecSheet是_Worksheet的对象,你之前要先得到worksheet
- Range m_ecRange = m_ecSheet.GetRange(COleVariant(beginS), COleVariant(endS));
- if(m_ecRange.m_lpDispatch)
- {
- //选择beginS, endS
- m_ecRange.Select();
- //设置为文本格式
- m_ecRange.SetNumberFormatLocal(COleVariant("@"));
- return TRUE;
- }
- return FALSE;
- }
调用方法:SetTextFormat(“A5”, “J64”)
但是用上面的方法设置之后,原来是数字格式的单元格仍然不是文本格式,如果直接用VC操作会出错,这里有一种区分数字是否真正转为文本格式的方法:
下图左是按照上述方法设置后的结果,此时,数字仍然不是真正的文本,下图右则是真正的文本,它的特点是每个数字格左上角都有一个绿色的小三角。
那么如果将数字设置为真正的文本呢?我们按如下步骤进行。
第一步:手动设置方法
选中一列,按数据-》分列
直接按下一步
直接按下一步
这里要选择文本,红笔标出,然后按完成,此时,数字就变成真正的文本了。
第二步:上述过程用宏记录下来是这样的:
- Range("A5:A64").Select
- Selection.TextToColumns Destination:=Range("A5"), DataType:=xlDelimited, _
- TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
- Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
- :=Array(1, 2), TrailingMinusNumbers:=True
第三步:将其转为VC来实现
- _Worksheet m_ecSheet;//首先你要自己初始化哦!!!!
- Range m_ecRange;
- BOOL CExcelOperate::GetRangeAndValue(CString begin, CString end)
- {
- if(!m_ecSheet.m_lpDispatch)
- {
- AfxMessageBox("Sheet获取失败!", MB_OK|MB_ICONWARNING);
- return FALSE;
- }
- m_ecRange = m_ecSheet.GetRange(COleVariant(begin), COleVariant(end));
- if(!m_ecRange.m_lpDispatch)
- {
- AfxMessageBox("Range获取失败!", MB_OK|MB_ICONWARNING);
- return FALSE;
- }
- ret = m_ecRange.GetValue2();//得到表格中的值
- return TRUE;
- }
- BOOL CExcelOperate::SetRowToTextFormat(CString &beginS, CString &endS)
- {
- if(GetRangeAndValue(beginS, endS))
- {
- m_ecRange.Select();
- Range m_tempRange = m_ecSheet.GetRange(COleVariant(beginS), COleVariant(beginS));
- if(!m_tempRange.m_lpDispatch) return FALSE;
- COleVariant vTrue((short)TRUE),
- vFalse((short)FALSE);
- int tempArray[2] = {1, 2};
- COleSafeArray saRet;
- DWORD numElements = {2};
- saRet.Create(VT_I4, 1, &numElements);
- long index = 0;
- int val = 1;
- saRet.PutElement(&index, &val);
- index++;
- val = 2;
- saRet.PutElement(&index, &val);
- //m_tempRange.GetItem(COleVariant((short)5),COleVariant("A"));
- m_ecRange.TextToColumns(m_tempRange.GetItem(COleVariant((short)1),COleVariant((short)1)), 1, 1, vFalse, vTrue, vFalse, vFalse, vFalse, vFalse, vFalse, saRet, vFalse, vFalse, vTrue);
- m_tempRange.ReleaseDispatch();
- return TRUE;
- }
- return FALSE;
- }
【MFC/C++ 操作Excel】C++下TextToColumns函数的参数
我们在使用excel的分列将数字转为文本时,用宏记录的vb代码如下:
- Range("A5:A64").Select
- Selection.TextToColumns Destination:=Range("A5"), DataType:=xlDelimited, _
- TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _
- Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _
- :=Array(1, 2), TrailingMinusNumbers:=True
如果我们想将其转为VC代码,过程如下:
第一句:
- Range("A5:A64").Select
这一句表示选中A5:A64,翻译为C++,就是
- m_ecRange.Select();
其中m_ecRange是Range的对象。
第二句:
- Selection.TextToColumns Destination:=Range("A5"), DataType:=xlDelimited, _ TextQualifier:=xlDoubleQuote, ConsecutiveDelimiter:=False, Tab:=True, _ Semicolon:=False, Comma:=False, Space:=False, Other:=False, FieldInfo _ :=Array(1, 2), TrailingMinusNumbers:=True
其对应的是Range类的TextToColumns函数,其C++函数原型是
- VARIANT TextToColumns(const VARIANT& Destination, long 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& DecimalSeparator, const VARIANT& ThousandsSeparator, const VARIANT& TrailingMinusNumbers);
各个参数的意思可以参见:
http://bbs.csdn.net/topics/390285992
这里的参数只有第1个const VARIANT& Destination和第11个const VARIANT& FieldInfo比较难确定,其他参数都可以通过在宏中用MsgBox得到,下面说明这两个参数:
第1个参数(const VARIANT& Destination):
MSDN解释:指定 Microsoft Excel 放置结果的位置的 Range 对象。如果该区域大于一个单元格,请使用左上角的单元格。
所以这里我们设置为A5单元格,我们可以使用:
- CString beginS = “A5”;//将beginS设置为这一列左上角的单元格
- Range m_tempRange = m_ecSheet.GetRange(COleVariant(beginS), COleVariant(beginS));//得到该单元格的range
- m_tempRange.GetItem(COleVariant((short)1),COleVariant((short)1));//返回的值就是要传入的值,也就是左上角单元格,这里一定是1,1,因为range只有一个单元格
第11个参数(const VARIANT& FieldInfo)
MSDN解释:包含单列数据拆分信息的数组。对本参数的解释取决于 DataType 的值。如果此数据由分隔符分隔,则本参数为由两元素数组组成的数组,其中每个两元素数组指定一个特定列的转换选项。第一个元素为列标(从 1 开始),第二个元素是 xlColumnDataType 常量之一,用以指定该列的拆分方式。
我们可以看到VB代码是Array(1, 2),是一个一维数组,数组有2个元素,数组的第一个元素是1,第二个元素是2;在MFC中,我们要使用
COleSafeArray来代表数组,初始化这样一个数组如下:
- COleSafeArray saRet;
- DWORD numElements = {2};//数组中有2个元素
- saRet.Create(VT_I4, 1, &numElements);//第一个参数表示存入int,第二个参数表示是一维数组,第三个参数表示数组中有2个元素
- long index = 0;//数组下标
- int val = 1;//值
- saRet.PutElement(&index, &val);//将0下标的值设置为1
- index++;
- val = 2;
- saRet.PutElement(&index, &val);//将1下标的值设置为2<p> </p>
整个函数如下:
- BOOL CExcelOperate::SetRowToTextFormat(CString &beginS, CString &endS)
- {
- if(GetRangeAndValue(beginS, endS))
- {
- m_ecRange.Select();
- Range m_tempRange = m_ecSheet.GetRange(COleVariant(beginS), COleVariant(beginS));
- if(!m_tempRange.m_lpDispatch) return FALSE;
- COleVariant vTrue((short)TRUE),
- vFalse((short)FALSE);
- //int tempArray[2] = {1, 2};
- COleSafeArray saRet;
- DWORD numElements = {2};
- saRet.Create(VT_I4, 1, &numElements);
- long index = 0;
- int val = 1;
- saRet.PutElement(&index, &val);
- index++;
- val = 2;
- saRet.PutElement(&index, &val);
- //m_tempRange.GetItem(COleVariant((short)5),COleVariant("A"));
- m_ecRange.TextToColumns(m_tempRange.GetItem(COleVariant((short)1),COleVariant((short)1)), 1, 1, vFalse, vTrue, vFalse, vFalse, vFalse, vFalse, vFalse, saRet, vFalse, vFalse, vTrue);
- m_tempRange.ReleaseDispatch();
- return TRUE;
- }
- return FALSE;
- }
- BOOL CExcelOperate::GetRangeAndValue(CString begin, CString end)
- {
- if(!m_ecSheet.m_lpDispatch)
- {
- AfxMessageBox("Sheet获取失败!", MB_OK|MB_ICONWARNING);
- return FALSE;
- }
- m_ecRange = m_ecSheet.GetRange(COleVariant(begin), COleVariant(end));
- if(!m_ecRange.m_lpDispatch)
- {
- AfxMessageBox("Range获取失败!", MB_OK|MB_ICONWARNING);
- return FALSE;
- }
- ret = m_ecRange.GetValue2();//得到表格中的值
- return TRUE;
- }