MFC Execl文件读写及插入图片

时过境迁,时隔多个月之后,重新总结一些东西,工作是为生活。

C++读取Excel文件的方法有很多,但是也许就是因为方法太多,大家在选择的时候会很疑惑。
对于多种不同方法的区别和介绍,网上都比较详细。比如参考 https://www.cnblogs.com/whwywzhj/p/9176833.html

而并未过多深入研究。

一、一般我们只是进行简单的读写操作,可以通过C语言读写程序来实现

第一步:单纯C语言写入Excel文件只能是 *.csv的后缀文件(是和txt一样,以二进制文本形式存储,它是以都逗号分隔符做个单元格内容的划分, .xls存储比较复杂, .csv文件可以可以通过.xls或者.xlsx文件另存为,选择.csv文件格式),它们可以通过Notepad++等记事本软件当做txt文件打开。

需要注意的是:当对*.xls文件写入或者读取之后,再打开Excel文件时会弹出格式兼容的提示窗口,因为这样的C语言操作Excel文件是当文本文件打开操作的,所以会忽略原有格式,但是不影响,点击“是(Y)”即可,如下图所示:
在这里插入图片描述

第二步:对表格的处理,使用C语言打开表格后,文件指针指向整个表格的第1行第1列。
如果要给它的下一个同行单元格(第1行第2列)写数据,使用"\t" ;
如果要给它的下一个同列单元格(第2行第1列)写数据,使用"\n" 。

void writeExcel()
{
	char chy[4]={ 'x' ,'a' ,'h','w' } ;
	int data[4]={ 1 , 3 , 6 ,9	};
	int i ;
	FILE *fp = NULL ;
	fp = fopen("G:\\Desktop\\test.csv","w") ;
	for (i=0 ; i<4 ;i++)
		fprintf(fp,"%c\t%d\n",chy[i],data[i] ) ;
	fclose(fp);
}
void main()
{					
	writeExcel()  ;	
}

这些都是从网上的大佬那里偷学而来,当然有一些自己的总结,嘻嘻。下面是我实际使用的代码。

void writeExcel()
{
	int data[4]={ 1 , 3 , 6 ,9	};

	ofstream outfile_final_result;
	outfile_final_result.open("D:/测量结果.txt", ios::in | ios::trunc);

	outfile_final_result << "序号" << ',' << "结果" << endl; //第一行
	for (i=0 ; i<4 ;i++)
	{
		outfile_final_result << i + 1 << ',' << data[i] << endl;
	}
	outfile_final_result.close();
}
void main()
{					
	writeExcel()  ;	
}

这里我使用了 << ‘,’ << 来代替 \t ,用 << endl; 来代替 换行。这些都看个人喜欢。

缺点:单元格内的内容不能太长,不能自适应,不能居中等操作,只适用于简单的数据存储,可以理解为txt文件。


二、其中在 MFC 中操作 Office 通过 vs 导入 OLE/COM 组件来实现对 Office 的操作,但是操作稍微复杂些,下面就针对这种方法来介绍:

环境:

Windows 10 (64位)

Microsoft Visual Studio 2015

Office 2016 (64位)

步骤:

1、安装 Office 2016

由于是用 vs 导入 Office 的 OLE/COM 组件来进行读写操作,所以必须先安装 Office。

2、创建一个空的 MFC 对话框项目
3、导入操作 Excel 的几个基本类
右击项目,选择“类向导”;

在这里插入图片描述

“添加类” --> "类型库中的MFC类" 

在这里插入图片描述
选择 Excel 的 OLE/COM 组件,默认在 C 盘,除非你修改了安装目录。【还有另一种方式可以弹出这个界面:右击项目–>添加 --> 类 --> MFC --> ActiveX 控件中的 MFC 类】

在这里插入图片描述
从左侧选择接口 _Application、Workbooks、_Workbook、Worksheets、_Worksheet、Range、Shapes、Shape、ShapeRange、_Font、_nterior ,他们分别对应的类是 CApplication、CWorkbooks、CWorkbook、CWorksheets、CWorksheet、CRange、CShapes、CShape、CShapeRange、CFont0、Cnterior。然后就可以看到导入的这些类。
当然也可以直接copy别的号的项目的文件就行。

在这里插入图片描述

CWorkbooks:工作薄的容器;
CWorkbook:单个工作薄;
CWorksheets:单个工作簿中的Sheet表格的容器;
CWorksheet:单个Sheet表格;
CRange:单个或多个单元格;
CShapes:形状容器;
CShape:形状;
CShapeRange:形状所占的单元格范围;

4、解决导入 Excel 接口存在的问题
将每个类头文件中的 "#import "C:\\Program Files (x86)\\Microsoft Office\\Office15\\EXCEL.EXE" no_namespace"注释掉。
将头文件 CRange.h 中的 DialogBox 前面添加下划线 _DialogBox 即可解决问题,修改后如下所示。

VARIANT _DialogBox()
{
	VARIANT result;
	InvokeHelper(0xf5, DISPATCH_METHOD, VT_VARIANT, (void*)&result, NULL);
	return result;
}
5、导入头文件和类型库
#pragma once
#include "CApplication.h"
#include "CWorkbook.h"
#include "CWorkbooks.h"
#include "CWorksheet.h"
#include "CWorksheets.h"
#include "CRange.h"
#include "CFont0.h"
#include "Cnterior.h"
#include "CShape.h"
#include "CShapes.h"
#include "CShapeRange.h"

#include <string>
#include <sstream>

using namespace std;

头文件定义变量:

CApplication m_ExcelApp;
CWorkbook m_ExcelBook;
CWorkbooks m_ExcelBooks;
CWorksheet m_ExcelSheet;
CWorksheets m_ExcelSheets;
CRange m_ExcelRange;
CRange m_ExcelCols;
CFont0 m_ExcelFont;
Cnterior current_interior;

CString m_openFilePath;
CString m_saveFilePath;

6、操作 Excel 步骤

(1)创建一个Excel应用程序。

(2)得到Workbook的容器。

(3)打开一个Workbook或者创建一个Workbook。

(4)得到Workbook中的Worksheet的容器。

(5)打开一个Worksheet或者创建一个WorkSheet。

(6)通过Range对WorkSheet中的单元格进行读写操作。

(7)如果导入图片,通过Shape来操作。

(8)保存Excel。

(9)释放资源。

//创建execl表格
void ExcelRW::OpenTable(CString OpenPath)
{
	m_openFilePath = OpenPath;
	if (!m_ExcelApp.CreateDispatch(_T("Excel.Application")))
	{
		AfxMessageBox(_T("居然你连OFFICE都没有安装吗?"), MB_OK | MB_ICONWARNING);
		return;
	}

	m_ExcelApp.put_Visible(FALSE); //是否显示execl 
	m_ExcelApp.put_UserControl(FALSE);
	m_ExcelApp.put_DisplayFullScreen(FALSE);//设置全屏显示
	m_ExcelApp.put_DisplayAlerts(FALSE);//屏蔽警告

	/*打开工作簿*/
	m_ExcelBooks = m_ExcelApp.get_Workbooks();        
	try
	{
		m_ExcelBook = m_ExcelBooks.Add(_variant_t(m_openFilePath));//打开execl文件
	}
	catch (CException* e)
	{
		m_ExcelBook = m_ExcelBooks.Add(vtMissing);//找不到就新建一个
	}

	
	/*得到工作薄中1Sheet容器*/
	m_ExcelSheets.AttachDispatch(m_ExcelBook.get_Worksheets());
	//m_ExcelSheet = m_ExcelBook.get_ActiveSheet();//获取当前工作表
	m_ExcelSheet = m_ExcelSheets.get_Item(COleVariant((short)1));//获取第一个工作表
}
//关闭execl
void ExcelRW::CloseTable(CString strSavePath)
{
	m_saveFilePath=strSavePath;
	m_ExcelBook.SaveCopyAs(COleVariant(m_saveFilePath));
	m_ExcelBook.put_Saved(TRUE);
	// 释放对象
	m_ExcelBooks.ReleaseDispatch();
	m_ExcelBook.ReleaseDispatch();
	m_ExcelSheets.ReleaseDispatch();
	m_ExcelSheet.ReleaseDispatch();
	m_ExcelRange.ReleaseDispatch();

	m_ExcelApp.Quit();
	m_ExcelApp.ReleaseDispatch();
}
//写数据到表格单元,clocow为表格位置(比如“A5”),strWrite为要写入的字符
void ExcelRW::WriteTable(CString clocow,CString strWrite)
{
	m_ExcelRange = m_ExcelSheet.get_Range(COleVariant(clocow), COleVariant(clocow));
	m_ExcelRange.put_Value2(COleVariant(strWrite)); 
	//选择整列,并设置宽度为自适应
	m_ExcelCols = m_ExcelRange.get_EntireColumn();     
	m_ExcelCols.AutoFit();
}

但在这里感觉还是不方便,所以做了一些优化。

//获得单元格的名称,比如 2行3列= C2
string ExcelRW::GetCellName(int irow, int icol)
{
	//将int类型的irow转换为string类型的srow
	string srow;
	string scol;
	string result;
	stringstream sstemp;
	sstemp << irow;
	sstemp >> srow;
	//当列数小于等于26时 返回值为单个字母+数字
	if (icol <= 26 && icol > 0)
	{
		char ctemp = 'A';
		ctemp = 'A' + icol - 1;
		result = ctemp + srow;
		return result;
	}
	//目前只考虑列数范围在ZZ以内
	//当列数大于26时 返回值为两个字母+数字 
	else if (icol > 26)
	{
		//ctemp1 表示第一个字母
		char ctemp1 = 'A';
		//ctemp2 表示第二个字母
		char ctemp2 = 'A';
		int itemp1 = (icol - 1) / 26 - 1;
		int itemp2 = icol % 26 - 1;
		if (itemp2 == -1)
		{
			itemp2 = 25;
		}
		ctemp1 = 'A' + itemp1;
		ctemp2 = 'A' + itemp2;
		//将字符类型转换为字符串类型
		stringstream sstemp1;
		stringstream sstemp2;
		sstemp1 << ctemp1;
		sstemp2 << ctemp2;
		scol = sstemp1.str() + sstemp2.str();
		result = scol + srow;
		return result;
	}
}
//写入一个Cell中一个int型数据
BOOL ExcelRW::SetCellInt(int irow, int icol, int new_int)
{
	if (irow > 0 && icol > 0)
	{
		string sint;
		stringstream sstemp;
		sstemp << new_int;
		sstemp >> sint;
		m_ExcelRange.put_Item(COleVariant(long(irow)), COleVariant(long(icol)), COleVariant(sint.c_str()));
		return TRUE;
	}
	else
	{ia
		return FALSE;
	}

}
//写入一个Cell中一个string型数据
BOOL ExcelRW::SetCellString(int irow, int icol, string new_string)
{
	if (irow > 0 && icol > 0)
	{
		m_ExcelRange.put_Item(COleVariant(long(irow)), COleVariant(long(icol)), COleVariant(new_string.c_str()));
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
//写入一个Cell中一个double型数据
BOOL ExcelRW::SetCellDouble(int irow, int icol, double new_double)
{
	if (irow > 0 && icol > 0)
	{
		string sdouble;
		stringstream sstemp;
		sstemp << new_double;
		sstemp >> sdouble;
		m_ExcelRange.put_Item(COleVariant(long(irow)), COleVariant(long(icol)), COleVariant(sdouble.c_str()));
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

还有一些常用的函数,后续函数可以一起补充,都是很简单的。

//设置单个单元格的颜色
void ExcelRW::SetCellColor(int irow, int icol, int red, int green, int blue)
{
	m_ExcelRange = m_ExcelSheet.get_Range(COleVariant(GetCellName(irow, icol).c_str()), COleVariant(GetCellName(irow, icol).c_str()));
	m_ExcelFont.AttachDispatch(m_ExcelRange.get_Font());
	m_ExcelFont.put_Color(_variant_t(RGB(red, green, blue)));
}

//设置单个单元格的背景颜色	
	//icolor<=56  icolor(常用) = 1黑 /2白 /3红 /4绿 /5蓝 /6黄 /7紫 /8青 
void ExcelRW::SetCellBackground(int irow, int icol, int icolor)
{
	m_ExcelRange = m_ExcelSheet.get_Range(COleVariant(GetCellName(irow, icol).c_str()), COleVariant(GetCellName(irow, icol).c_str()));
	current_interior.AttachDispatch(m_ExcelRange.get_Interior());
	current_interior.put_ColorIndex(_variant_t(icolor));
}

//设置单个单元格的字体风格,比如 "宋体"、"华文行楷"
void ExcelRW::SetCellFont(int irow, int icol, const char *font)
{

	m_ExcelRange = m_ExcelSheet.get_Range(COleVariant(GetCellName(irow, icol).c_str()), COleVariant(GetCellName(irow, icol).c_str()));
	m_ExcelFont.AttachDispatch(m_ExcelRange.get_Font());
	m_ExcelFont.put_Name(_variant_t(font));
}
7、载入图像数据
//向已存在的Excel中导入图片,放在固定位置
void ExcelRW::ImportImage2Excel(CString imagePath, int startIndex_irow, int startIndex_icol, int endIndex_irow, int endIndex_icol)
{

	//获取图像插入的范围
	//从Sheet对象上获得一个Shapes   
	CShapes pShapes;
	pShapes.AttachDispatch(m_ExcelSheet.get_Shapes());
	//获得Range对象,用来插入图片
	CRange range = m_ExcelSheet.get_Range(COleVariant(GetCellName(startIndex_irow, startIndex_icol).c_str()), COleVariant(GetCellName(endIndex_irow, endIndex_icol).c_str()));

	VARIANT rLeft = range.get_Left();
	VARIANT rTop = range.get_Top();
	VARIANT rWidth = range.get_Width();
	VARIANT rHeight = range.get_Height();
	long msoFalse = 1, msoTrue = 1;
	//添加图像到 H1 - K10范围区域
	CShape pShape = pShapes.AddPicture(imagePath, msoFalse, msoTrue,
		(float)rLeft.dblVal, (float)rTop.dblVal, (float)rWidth.dblVal, (float)rHeight.dblVal);
	//设置图像所占的宽高
	CShapeRange shapeRange = pShapes.get_Range(_variant_t(long(1)));
	shapeRange.put_Height((float)rHeight.dblVal);
	shapeRange.put_Width((float)rWidth.dblVal);

}

后续包括合并单元格,设置边框等等操作。学无止境。

另外参考博主。

例子在这:https://download.csdn.net/download/cao_jie_xin/13101573

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值