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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • JavaScript 基本知识

    JavaScript 基本知识bilibiliJS视频链接:https://www.bilibili.com/video/BV1W54y1J7Ed?p=2&spm_id_from=pageDrivervscode配置html:https://blog.csdn.net/caohongxing/article/details/108632859目录JS来源JavaScript核心由三部分组成书写位置:行内式,内嵌式,外链式变量:var准备一个容器,变量名有规格且区分大小写JS中的数据:基本数据类型和引用数据类型.

    2022年10月20日
    0
  • HBase Shell命令大全「建议收藏」

    HBase Shell命令大全「建议收藏」HBase关键名称:RowKey列族columnfamily单元Cell时间戳timestampHBaseShell是官方提供的一组命令,用于操作HBase。如果配置了HBase的环境变量了,就可以知己在命令行中输入hbaseshell命令进入命令行。hbaseshellhelp命令可以通过help’命名名称’来查看命令行的具体使用查询服务器状态st…

    2022年7月16日
    12
  • 数据库索引的作用和长处缺点

    数据库索引的作用和长处缺点

    2021年12月6日
    47
  • Linux下视频流媒体服务器搭建详解「建议收藏」

    Linux下视频流媒体服务器搭建详解「建议收藏」目标用于搭建内网流媒体服务器支持视频的点播。背景用于支持培训网站中视频点拨功能,在培训网站总体方案中需要加入流媒体服务器,用于存储和传输视频资源。相关概念流媒体流媒体(StreamingMedia)是一种新兴的网络传输技术,在互联网上实时顺序地传输和播放视/音频等多媒体内容的连续时基数据流。流媒体技术包括流媒体数据采集、视/音频编解码、存储、传输、播放等领域。流媒体系统组成包括编码工具、流媒体数…

    2022年10月20日
    1
  • KDE自动登录

    KDE自动登录

    2021年8月18日
    66
  • linux查看端口号占用命令-netstat

    linux查看端口号占用命令-netstat题记经常会发现,很多时候我们在运行一些带有端口的程序时,程序经常会报端口被占用的问题,比如Tomcat8080,端口起不来。查看端口号netstat如果发现某个端口被占用后,可以用命令查看,该端口到底是被哪个进程所占用。命令如下:netstat-pan|grep5623#其中5623位端口号如图:发现5623的端口,被28425的进程id所占用,继

    2022年7月23日
    11

发表回复

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

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