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


相关推荐

  • mysql锁机制_类加载机制的作用和过程

    mysql锁机制_类加载机制的作用和过程Mysql锁:在多线程当中如果想保证数据的准确性是如何实现的呢?没错,通过同步实现。同步就相当于是加锁。加了锁以后有什么好处呢?当一个线程真正在操作数据的时候,其他线程只能等待。当一个线程执行完毕后,释放锁。其他线程才能进行操作!那么我们的MySQL数据库中的锁的功能也是类似的,处理事务的隔离性中,可能会出现脏读、不可重复读、幻读的问题,所以,锁的作用也可以解决这些问题!在数据库中,数据是一种供许多用户共享访问的资源,如何保证数据并发访问的一致性、有效性,是所有数据库必须解决的一个问题,

    2022年9月28日
    0
  • 使用javascript实现数组截取

    使用javascript实现数组截取前言:在开发项目的过程中遇到这样的一个问题,就是需要对接口查询出来的数据两个两个的进行截取,之后分别两个两个的放入数组中,再把这些数组放到一个新数组中,实现方法如下:方法一:functionarrayChunk(array,size){ letdata=[]; for(leti=0;i<array.length;i+=size){ data.push(array.slice(i,i+size)) } returndata;}arrayChunk([{i

    2022年6月5日
    35
  • 冒泡插入[通俗易懂]

    冒泡插入[通俗易懂]冒泡插入

    2022年4月24日
    44
  • 前端请求后台报错400

    前端请求后台报错400前端请求后台报错400

    2022年5月6日
    124
  • 数人云|优势+工具+实践=DevOps&Docker的企业级落地

    数人云|优势+工具+实践=DevOps&Docker的企业级落地

    2022年3月5日
    35
  • Zabbix监控mysql主从状态

    Zabbix监控mysql主从状态首先我们要监控主从是否正常同步,那么我们需要知道的是,什么东西或者说现象可以判断它的主从复制是正常的是正确的。如上图所示,上述两个参数若同时为yes则说明主从同步正常。那么我们现在就需要用命令去把这个正确的主从复制的状态表达出来。mysql-uroot-p123456-S/data/mysql/3308/mysql3308.sock-e”showslavestatus\G”|…

    2022年5月25日
    37

发表回复

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

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