2023年12月11日发(作者:)

少年易学老难成,一寸光阴不可轻 - 百度文库

广丰鄂

摘要:

程序利用微软提供的excel操作的库函数读入数据,再调用MFC中的CDC类进行固定位置打印。

内容:

程序主要分两步:第一步从excel读取数据。第二步把excel读入的数据打印到纸张的固定位置。

从excel读取数据

一:准备工作

开始新建基于对话框的工程,记得在第四个向导中选择作为静态链接库导入。新建好之后导入excel操作库函数,依次选择View -> ClassWizard ->Add New Class

->From a type library。在弹出的对话框中选择装excel的安装目录,选择,然后添加类,主要类型有_Applicaiton, Workbooks, _Workbook, Worksheets,

_Wordsheet, Range类,其他类型可根据需要自己添加。

Excel接口类中层次如下所示:

-_Application

-Workbooks 工作薄集合

-_Workbook 工作薄

-Worksheets 工作表集合

-_Worksheet 工作表

-Range单元格区域

(在程序中可能还会使用到word类库,导入步骤一样,添加的类有_Application,

Documents, _Document, Selection, 因为word中的类可能与excel中的类名有冲突,可以在冲突的类中添加命名空间,在头文件和源文件中重复的类都包含到一个命名空间,这样就可以有效解决导入两个不同库而出现的类同名的问题)

导入excel库后,可以先看下导入的类提供的函数有哪些,一般可以根据其名字判断该函数的作用,如果不清楚你要做的步骤应该包含哪些函数,可以试下excel中提供的宏:

1.先打开excel应用程序,点击工具->宏->录制宏,开始录制。

2.进行你想要的操作,比如多打开工作博,或者添加工作簿,或者其他操作,操作结束后,点击结束宏。

3.查看录制的宏,点击工具->宏->宏。。。查看宏,本操作是一个已存在的文件,得到的宏如图1所示:

1 少年易学老难成,一寸光阴不可轻 - 百度文库

图1 打开存在文件的宏

4.分析宏,发现打开文件是在Wordbooks类的操作,使用的是Workbooks中的Open函数,然后可以查看导入的库中的Workbooks下的Open函数,选择正确的参数,即可执行打开文件操作。Workbooks下的Open函数原型如下:

PDISPATCH Workbooks::Open(LPCTSTR Filename, const VARIANT&

UpdateLinks, const VARIANT& ReadOnly, const VARIANT& Format, const

VARIANT& Password, const VARIANT& WriteResPassword, const VARIANT&

IgnoreReadOnlyRecommended, const VARIANT& Origin, const VARIANT&

Delimiter, const VARIANT& Editable, const VARIANT& Notify, const VARIANT&

Converter, const VARIANT& AddToMru, const VARIANT& Local, const

VARIANT& CorruptLoad);

会发现类中函数的参数几乎都是VARIANT类型的参数,Variant 是一种特殊的数据类型,除了定长String数据及用户定义类型外,可以包含任何种类的数据。Variant 也可以包含Empty、Error、Nothing及Null等特殊值。可以用VarType函数或TypeName函数来决定如何处理 Variant 中的数据。

可能会对这些类型不太了解,不过也没关系,碰到不明白的参数,不知道要填什么的时候,可以使用默认参数,默认参数可定义为如下:

COleVariant vTrue((short)TRUE);

COleVariant vFalse((short)FALSE);

COleVariant vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);

准备工作就算完成了,接着就是正式使用编写代码操作excel了。

二:正式操作:

1.首先打开工程名 + Dlg结尾的对话框源文件,在头部添加#include “excel.h”和#include “atlbase.h”,要在文件中使用excel库函数,首先必须在此文件包含excel的头文件,atlbase是为了操作简单。

2.在功成名 + App结尾的源文件中的InitInstance中加入如下代码:

if (!AfxOleInit())

{

AfxMessageBox("初始化Ole失败!");

return FALSE;

}

3.在想要执行excel操作的程序函数或消息响应代码中添加对excel的代码。

A.首先定义类的对象:

spaceExcel::_Application excelApp;

Workbooks excelWorkBooks;

_Workbook excelWorkBook;

Worksheets excelWorkSheets;

_Worksheet excelWorkSheet;

2 少年易学老难成,一寸光阴不可轻 - 百度文库

Range excelRange, usedRange;

在_Application类中添加了一个命名空间并把此类包含在命名空间中。

B.打开excel应用程序:

if(excelApp == NULL){

if(!Dispatch(_T("ation")))

{

AfxMessageBox("系统检测到您的电脑尚未安装excel!,请先安装excel");

return;

}

}

如果想要看到此excel表格,可以在花括号后面添加:

ible(TRUE);

rControl(TRUE); //和word的区别。如果不加这句excel一闪就关

C.获得工作簿集合,工作簿,工作表集合,和工作表:

excelWorkBooks = kbooks();

excelWorkBook = (m_excelPathName, vOpt, vTrue, vOpt,

vOpt, vOpt, vOpt, vOpt, vOpt, vFalse, vOpt, vOpt, vOpt, vOpt, vOpt);

excelWorkSheets = ksheets();

excelWorkSheet = m(COleVariant((short)1));

具体参数和函数可参考类库。

D.获得已使用的行,列,得到行列的使用数目:

usedRange = dRange();

excelRange = s();

long iRowNum = nt();

excelRange = umns();

long iColumnNum = nt();

E.获得每个单元格的值:

VARIANT ret;

ret = ue(vOpt);

COleSafeArray sa(ret);

long lNumRows;

long lNumCols;

und(1, &lNumRows);

und(2, &lNumCols);

long index[2];

VARIANT val;

CString str = "";

int row, column;

3 少年易学老难成,一寸光阴不可轻 - 百度文库

for(row = m_startLocation; row <= iRowNum; row++){

for(column = 1; column <= iColumnNum; column++){

index[0] = row;

index[1] = column;

ment(index, &val);

switch(){

case VT_R8:

("%.2f", );

break;

case VT_BSTR:

str = (CString)l;

break;

case VT_EMPTY:

str = "";

break;

}

(str); //以CString保存单元格值

}

}

读取操作完成,如果要保存读取数据,可以使用CStringArray类型保存。

打印部分:

刚开始,不知道如何打印,网上百度,对于基于文档类型的工程实现打印很简单,但是基于对话框打印的就蛮复杂,看不怎么懂,网上代码也比较少。因此跑到学校图书馆去借书看,发现书上的简单也容易多了。通过CDC类自己编写打印功能。

一、准备工作

1.分辨率:分辨率是一个表示平面图像惊喜程序的概念,通常以横向和纵向点的数量来衡量的,表示水平点*垂直点的形式,在一个平面内,显示的点越多,分辨率就越高,显示的图像越细致,分辨率的种类有很多,主要了解下屏幕分辨率和设备分辨率。

屏幕分辨率:觉得出现在屏幕上的信息数量(以像素为单位)的设置,低分辨率能使屏幕上项目大一些,但屏幕区域会变小,高分辨率扩大了整个屏幕区域,但单个项目会变小。

设备分辨率:又称输出分辨率,指的是各类输出设备每英寸可产生的点数,如显示器,喷墨打印机,激光打印机,绘图仪的分辨率。这种分辨率通过DPI衡量,PC显示器的设备分辨率一般在60~120DPI之间,而打印设备的分辨率在360~1440DPI之间。

2.映射模式:

因为分辨率的不同,因此需要一种映射模式来解决这个问题,使打印效果和屏幕上显示的相同。映射模式反映了逻辑设备单位与实际物理坐标单位之间的对应转4 少年易学老难成,一寸光阴不可轻 - 百度文库

换关系,映射模式可通过设备环境类的一个成员函数SetMapMode来设置。

Virtual int SerMapMode(int nMapMode);具体参数可参见MSDN。

二、正式操作:

添加一个按键,响应打印操作。在响应函数内部进行如下操作:

1.获取设备上下文。

A. 如果已经知道打印机的设备名称,可通过CDC类中的CreateDC方法创建打印机的设备上下文。

CDC tempdc;

DC(“”, “HP LaserJet 1020”, “”, “”);

具体参数可参见msdn。

B. 如果想要使用打印机设备而不知道设备名称,可以调用打印对话框使用户选择打印机,然后调用CPrintDialog类的GetPrinterDC方法获得设备上下文。

DWORD dwflags = PD_PAGENUMS | PD_HIDEPRINTTOFILE |PD_SELECTION;

CPrintDialog dlg(false, dwflags, NULL);

If(l() == IDOK)

{

CDC dc;

h(nterDC());

}

C. 如果不想选择打印机,也可以使应用程序调用当前机器默认的打印机,可以通过CPritDialog类的GetPrinterDC方法来实现,或者在构造打印机对话框时设置其具有PD_RETURNDEFAULT风格。

DWORD dwflags = PD_PAGENUMS | PD_HIDEPRINTTOFILE |

PD_RETURNDEFAULT;

CPrintDialog dlg(false, dwflags, NULL);

aults();

nterDC();

2.获得了设备上下文,接下来打印文本信息就很简单了。直接调用设备上下文类中提供的TextOut函数直接打印输出字符就可以了。不过为了准确定位,还得有一个好的映射:

A.首先定义个CDC* pDC = GetDC();用于获得对话框的的大小。然后用打印设备上下文CDC dc;获得他们之间的映射关系:

double ratex = iceCaps(LOGPIXELSX) /

pDC->GetDeviceCaps(LOGPIXELSX);

double ratey = iceCaps(LOGPIXELSY) /

pDC->GetDeviceCaps(LOGPIXELSY);

这个程序采用的是打印编辑框,把所有的编辑框ID设置为1,2,3。。。便于操作,定义两个CRect对象:一个是打印区域的大小,一个是编辑框的大小,获得他们的大小,并根据编辑框的位置在固定位置上打印编辑框的文本信息,具体代码如下:

CRect rect, framerect;

5 少年易学老难成,一寸光阴不可轻 - 百度文库

m_dowRect(&framerect);

char classname[255];

for(int i = 1; i <= 18; i++)

{

CWnd* control = this->GetDlgItem(i);

if(NULL != control)

{

CString str;

// CFont font;

control->GetWindowText(str);

control->GetWindowRect(&rect);

GetClassName(control->GetSafeHwnd(), classname, 255);

if(strcmp(classname, "Edit") == 0)

{

// PointFont(200 * ratex, "宋体");

t(( - ) * ratex, ( -

) * ratey, str);

}

}

}

m_Object();

();

3.可以使用DEVMODE结构控制打印。DEVMODE结构可以在msdn中查看。如改变文字方向:

DWORD dwflags = PD_ALLPAGES | PD_NOPAGENUMS |

PD_USEDEVMODECOPIES | PD_SELECTION | PD_HIDEPRINTTOFILE |

PD_RETURNDEFAULT

CPrintDialog dlg(false, dwflags, NULL);

If(l() == IDOK)

{

LPDEVMODE dv = Mode();

If(isHengXiang)

{

dv->dmOrientation = DMORIENT_LANDSCAPE;

}else{

dv->dmOrientation = DMORIENT_PORTRAIT;

}

CDC dc;

(nterDC());

(dv);

6 少年易学老难成,一寸光阴不可轻 - 百度文库

}

总结:

有这两个操作再加上MFC的一些基本操作和控件处理,就可以完成从excel中读出数据并以特定格式打印到打印纸上。

其实,如果要把excel数据用特定格式打印到纸面上,可以不用这么复杂,可以直接用excel直接完成上面的两个步骤。不过excel不怎么熟悉。没有具体步骤。

参考:

从excel读数据主要参考百度出来的各种网页上的代码,很详细,也很简单。

打印操作参考书:

Visual C++ 开发实战宝典, 宋珅等编著, 清华大学出版社2010年1月第1版。

ISBN:978 7 302 20905 8

7