C++ MFC实现list控件对Excel的读取

C++ MFC实现list控件对Excel的读取前面已经讲过了C++MFC程序对Excel文件的写入,链接如下:https://blog.csdn.net/V_Gogol/article/details/81782644后面很长时间没有更新读取数据操作,非常抱歉!看到网上有朋友问了读取的方法,于是就再写一了这一篇关于读取操作的博文。读取和写入大体相似,要引入的头文件和相关配置也是一样的,具体可以先看上面那一篇关于写入的博文,此篇为…

大家好,又见面了,我是你们的朋友全栈君。

前面已经讲过了C++ MFC程序对Excel文件的写入,链接如下:

https://blog.csdn.net/V_Gogol/article/details/81782644

后面很长时间没有更新读取数据操作,非常抱歉!看到网上有朋友问了读取的方法,于是就再写一了这一篇关于读取操作的博文。

读取和写入大体相似,要引入的头文件和相关配置也是一样的,具体可以先看上面那一篇关于写入的博文,此篇为了节省篇幅便于阅读,就只写读取的具体代码和解释。

我将读取和写入操作都封装成了一个专门的类,便于后续的调用:

list控件读取Excel数据

将Excel数据读取到mfc控件中,我写的函数适用于Excel文件列数和list控件列数相同的情况,此处提供源码,读者可根据源码改成更通用的情况。具体代码如下:

//参数为列表控件
void CFileRW::ExcelToList(CListCtrl *datalist)
{
    //文件对话框,打开具体Excel文件
	CFileDialog filedlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
		L"excel文件(*.xls)|*.xlsx|ALL Files(*.*)||");         //TRUE为打开,FALS为保存
	if (IDOK != filedlg.DoModal())
	{
		return;
	}
	//获取文件路径
	readxlspath = filedlg.GetPathName();
	if (!PathFileExists(readxlspath))
	{
		AfxMessageBox(readxlspath + "不存在");
		return;
	}
	if (!app.CreateDispatch(L"Excel.Application"))    //创建接口对象
	{
		AfxMessageBox(L"无法启动Excel服务器");
		return;
	}
	COleVariant	covOption((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
	//得到工作簿
	books.AttachDispatch(app.get_Workbooks());
	lpdisp = books.Open(readxlspath, covOption, covOption, covOption, covOption,
		covOption, covOption, covOption, covOption, covOption, covOption,
		covOption, covOption, covOption, covOption);
	//得到Workbook
	book.AttachDispatch(lpdisp);
	//sheets
	sheets.AttachDispatch(book.get_Worksheets());
	得到WorkSheet
	//sheet.AttachDispatch(sheets.get_sheet());
	//得到当前活跃sheet
	//如果有单元格正处于编辑状态,此操作不会返回,会一直等待
	lpdisp = book.get_ActiveSheet();
	sheet.AttachDispatch(lpdisp);
	usedrange.AttachDispatch(sheet.get_UsedRange());
	COleVariant vResult,vResult1;
	//读取已经使用区域的信息,包括已经使用的行数、列数、起始行、起始列
	range.AttachDispatch(sheet.get_UsedRange());
	//取得已经使用的行数
	range.AttachDispatch(range.get_Rows());
	long rownum = range.get_Count();
	//取得已经使用的列数
	range.AttachDispatch(range.get_Columns());
	long colnum = range.get_Count();
	//取得已使用区域的起始行,从1开始
	long startrow = range.get_Row();
	//取得已使用区域的起始列,从1开始
	long startcol = range.get_Column();
	//清空list控件内容
	datalist->DeleteAllItems();
	for (int i = startrow; i <= rownum; i++)
	{
		//先插入行首,即首列元素
		range.AttachDispatch(sheet.get_Cells());
		range.AttachDispatch(range.get_Item(_variant_t((long)i+1),
			_variant_t((long)startcol)).pdispVal);
		vResult = range.get_Value2();
		CString strread, stry0, strm0, strd0;
		SYSTEMTIME st0;
		if (vResult.vt == VT_BSTR)     //若是字符串
		{
			strread = vResult.bstrVal;
		}
		else if (vResult.vt == VT_R8) //8字节的数字
		{
			strread.Format(L"%f", vResult.dblVal);
		}
		else if (vResult.vt == VT_DATE) //时间格式
		{
			VariantTimeToSystemTime(vResult.date, &st0);
			stry0.Format(L"%d", st0.wYear);
			strm0.Format(L"%d", st0.wMonth);
			strd0.Format(L"%d", st0.wDay);
			strread = stry0 + L"-" + strm0 + L"-" + strd0;
		}
		else if (vResult.vt == VT_EMPTY) //单元为空
		{
			strread = L"";
		}
		else if (vResult.vt == VT_I4)
		{
			strread.Format(_T("%ld"), (int)vResult.lVal);
		};
		datalist->InsertItem(i , strread);

      //插入后面元素
		for (int j = startcol+1; j <= colnum; j++)
		{
			//读取单元格的值
			range.AttachDispatch(sheet.get_Cells());
			range.AttachDispatch(range.get_Item(_variant_t((long)i + 1),
				_variant_t((long)j)).pdispVal);
			vResult1 = range.get_Value2();
			CString str, stry, strm, strd;
			SYSTEMTIME st;
			if (vResult1.vt == VT_BSTR)     //若是字符串
			{
				str = vResult1.bstrVal;
			}
			else if (vResult1.vt == VT_R8) //8字节的数字
			{
				str.Format(L"%f", vResult1.dblVal);
			}
			else if (vResult1.vt == VT_DATE) //时间格式
			{
				VariantTimeToSystemTime(vResult1.date, &st);
				stry.Format(L"%d", st.wYear);
				strm.Format(L"%d", st.wMonth);
				strd.Format(L"%d", st.wDay);
				str = stry + L"-" + strm + L"-" + strd;
			}
			else if (vResult1.vt == VT_EMPTY) //单元为空
			{
				str = L"";
			}
			else if (vResult1.vt == VT_I4)
			{
				str.Format(_T("%ld"), (int)vResult1.lVal);
			}
			//datalist->SetItemText(static_cast<int>(i), static_cast<int>(j),str);
			datalist->SetItemText(i-1, j-1, str);
		}
	}
	release();
	AfxMessageBox(L"读取成功");
}

和写入时一样,读取完毕后也需要释放资源,我自己定义了一个资源释放函数release(),具体代码如下:

usedrange.ReleaseDispatch();
	range.ReleaseDispatch();
	sheet.ReleaseDispatch();
	sheets.ReleaseDispatch();
	book.ReleaseDispatch();
	books.ReleaseDispatch();
	app.Quit();
	app.ReleaseDispatch();

至此,mfc读取Excel就已经讲完了,后续会再更新一些简单的Excel样式控制,希望对大家有帮助,谢谢!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/150537.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vue3.0计算属性_vue计算属性什么时候执行

    vue3.0计算属性_vue计算属性什么时候执行前言一般情况下属性都是放到data中的,但是有些属性可能是需要经过一些逻辑计算后才能得出来,那么我们可以把这类属性变成计算属性。比如以下:<divid="example&quot

    2022年7月30日
    34
  • 关于我转生变成史莱姆这档事_kicker.de

    关于我转生变成史莱姆这档事_kicker.de1  请问什么所kworker进程 清理旧版本的软件缓存:  sudoapt-getautoclean这个进程是干什么的? 我的机器刚装11.04没次卡的时候top一下就发现kworker这个进程占用CPU很大,基本上都能到75%左右youmaytrytodisableallpowersavingcon

    2022年9月25日
    3
  • 如何成为运维架构师

    如何成为运维架构师在百度里搜索运维架构师,你会发现招聘的职位还不少并且月薪、年薪都很可观。提到架构师,大家都觉得挺神秘的,而作为运维领域的架构师,站在系统稳定和高可用、高扩展的角度,其承载着太多的责任和挑战。对于运维工程师来说,运维架构师就像是一个目标抑或是一座山峰。如何成为一名优秀的运维架构师?运维架构师应该具备何种职业素质?需要什么样的知识体系呢?一、职业素质运维架构师一词应该是与系统架构师、软件架构师、网络架构师、业务架构师不同的,虽然都是架构师,但侧重不同。在一个企业的IT系统中,运维架构师更需要具…

    2022年7月17日
    12
  • Laravel Model 的 fillable (白名单)与 guarded (黑名单)

    Laravel Model 的 fillable (白名单)与 guarded (黑名单)

    2021年10月25日
    53
  • Java中数组的定义与使用(一)「建议收藏」

    Java中数组的定义与使用(一)「建议收藏」如果说现在要求你定义100个整型变量,那么如果按照之前的做法,可能现在定义的的结构如下:inti1,i2,i3,…i100;但是这儿时候如果按照此类方式定义就会非常麻烦,…

    2022年6月2日
    34
  • vs2013安装失败解决办法_dns解析失败怎么解决

    vs2013安装失败解决办法_dns解析失败怎么解决个人解决方案:在控制面板-》软件卸载中将VisualC++2012redistributable、VisualC++2010redistributable相关的编程语言的东西卸载后,重启再安装就可以了。有个问题就是:在重启的过程中发现win10关机和启动花了很长时间,可能因为我卸载了上面这些组件导致其需要更新。关于VisualC++2012redistributable是什么,

    2022年8月12日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号