m_ListCtrl.InsertColumn(nCol,strHeader[nCol],LVCFMT_LEFT,nLong[nCol]);
}
④编译运行。
3.添加并修改“学生基本信息”对话框及其代码
①右击对话框,选中属性,创建“学生基本信息”对话框(ID为IDD_INPUT),在空白处双击鼠标,为其添加类CStuInfoDlg。
“学生基本信息”对话框
如上图设计该对话框,调整好各控件的位置。
左边控件的ID分别为:
IDC_EDIT_NAME,IDC_EDIT_NO,IDC_SEX(第一个Radio控件,同时它的“组”属性要选定;第二个Radio不管),IDC_BIRTHDAY,IDC_MAJOR。
“出生年月”的控件是选择日期时间选取器。
为控件关联成员变量:
控件ID
变量类型
变量名字
IDC_EDIT_NAME
CString
m_strName
IDC_EDIT_NO
CString
m_strNo
IDC_SEX
int
m_bMale
IDC_BIRTHDAY
CTime
m_tBirth
IDC_MAJOR
CString
m_strSpecial
②添加两个控件:
一个是静态文本控件,ID设为IDC_DRAW,选中“下沉”风格;另一个是按钮控件,标题为“插入照片”,ID为ID_BUTTON_PHOTO。
③为CStuInfoDlg类添加下列成员变量:
public:
BOOLm_bPhotoChange;//照片文件是否重新指定
HBITMAPm_hBitmap;//位图句柄
CStringm_strPhotoFilePath;//照片文件全路径名
④在CStuInfoDlg:
:
OnInitDialog中添加下列代码:
在Workspace的ClassView页面,右击CStuInfoDlg,选中AddWindowsMessageHandler…,在新建Windows消息/事件(N):
选中WM_INITDIALOG后按确定即可。
BOOLCStuInfoDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
…
if(!
m_strPhotoFilePath.IsEmpty()){
m_hBitmap=(HBITMAP):
:
LoadImage(AfxGetInstanceHandle(),m_strPhotoFilePath,
IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
//将外部BMP文件装载并返回HBITMAP句柄
}
m_bPhotoChange=FALSE;
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
⑤用MFCClassWizard为CStuInfoDlg类映射ID_BUTTON_PHOTO按钮的BN_CLICKED消息,并添加下列代码:
voidCStuInfoDlg:
:
OnButtonPhoto()
{
staticcharBASED_CODEszFilter[]="图片文件(*.bmp)|*.bmp||";
CFileDialogdlg(TRUE,NULL,NULL,OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
szFilter);
if(IDOK!
=dlg.DoModal())return;
m_bPhotoChange=TRUE;
m_strPhotoFilePath=dlg.GetPathName();
m_hBitmap=(HBITMAP):
:
LoadImage(AfxGetInstanceHandle(),m_strPhotoFilePath,
IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
Invalidate();//强制对话框无效,调用OnPaint
}
⑥为CStuInfoDlg类添加成员函数DrawPhoto,用于在静态文本控件IDC_DRAW中绘制照片。
voidCStuInfoDlg:
:
DrawPhoto()
{
if(!
m_hBitmap)return;
CBitmapm_bmp;
m_bmp.Attach(m_hBitmap);
BITMAPbm;//定义一个BITMAP结构变量,以便获取位图参数
m_bmp.GetObject(sizeof(BITMAP),&bm);
floatfScale;//高/宽
fScale=(float)bm.bmHeight/(float)bm.bmWidth;
CWnd*pWnd=GetDlgItem(IDC_DRAW);//获得IDC_DRAW控件窗口指针
CDC*pDC=pWnd->GetDC();//获得窗口当前的设备环境指针
//调整可以显示的矩形大小
CRectrcClient;
intnWidth,nHeight,nX=0,nY=0;
pWnd->GetClientRect(rcClient);
nWidth=rcClient.Width();
nHeight=(int)((float)nWidth*fScale);
nX=0;nY=(rcClient.Height()-nHeight)/2;
if(nHeight>rcClient.Height()){
nHeight=rcClient.Height();nWidth=(int)((float)nHeight/fScale);
nX=(rcClient.Width()-nWidth)/2;nY=0;
}
CDCdcMem;//定义并创建一个内存设备环境
dcMem.CreateCompatibleDC(pDC);
CBitmap*pOldbmp=dcMem.SelectObject(&m_bmp);//将位图选入内存设备环境中
rcClient.DeflateRect(-1,-1);
pDC->Rectangle(rcClient);
pDC->StretchBlt(nX,nY,nWidth,nHeight,
&dcMem,0,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
//将位图复制到实际的设备环境中
dcMem.SelectObject(pOldbmp);//恢复原来的内存设备环境
}
用MFCClassWizard为CStuInfoDlg类映射WM_PAINT消息,并添加下列代码:
voidCStuInfoDlg:
:
OnPaint()
{
CPaintDCdc(this);//devicecontextforpainting
CWnd*pWnd=GetDlgItem(IDC_DRAW);
pWnd->UpdateWindow();
DrawPhoto();
}
4.测试“学生基本信息”对话框
①在Ex_StudentView.cpp文件的开始处,添加包含CStuInfoDlg类的头文件包含:
#include"Ex_StudentView.h"
#include"StuInfoDlg.h"
②在菜单资源的主菜单中添加顶层菜单项“学生基本信息(&S)”,在该顶层菜单项中添加子菜单“添加(&A)”(ID_STUINFO_ADD)。
在工作区的ResourceView页面展开Accelerator,双击IDR_MAINFRAME,打开快捷键编辑器。
在空白区如下表添加:
③用MFCClassWizard为CEx_StudentView类添加处理菜单项ID_STUINFO_ADD的COMMAND消息,并添加下列代码:
voidCEx_StudentView:
:
OnStuinfoAdd()
{
CStuInfoDlgdlg;
if(dlg.DoModal()!
=IDOK)return;
}
④编译运行并测试。
5.完善OnStuinfoAdd代码
①为CEx_StudentView类添加成员函数DoCopyFile,用于复制文件,其代码如下:
voidCEx_StudentView:
:
DoCopyFile(CStringstrFileTo,CStringstrFileFrom)
{
CFilefileFrom,fileTo;
if(!
fileFrom.Open(strFileFrom,CFile:
:
modeRead)){
AfxMessageBox("源文件无法打开,复制失败!
");return;
}
fileTo.Open(strFileTo,CFile:
:
modeCreate|CFile:
:
modeWrite);
BYTEbuffer[4096];
DWORDdwRead;
do{
dwRead=fileFrom.Read(buffer,4096);
fileTo.Write(buffer,dwRead);
}while(dwRead>0);
fileFrom.Close();
fileTo.Close();
}
②在CEx_StudentView:
:
OnStuinfoAdd函数中添加下列代码:
voidCEx_StudentView:
:
OnStuinfoAdd()
{
//TODO:
Addyourcommandhandlercodehere
CStuInfoDlgdlg;
if(dlg.DoModal()!
=IDOK)return;//复制照片文件
CStringstrFileTO;
strFileTO.Format("c:
//%s.bmp",dlg.m_strNo);
if(!
dlg.m_strPhotoFilePath.IsEmpty())
DoCopyFile(strFileTO,dlg.m_strPhotoFilePath);
//添加列表项
CListCtrl&m_ListCtrl=GetListCtrl();
intnItem=m_ListCtrl.GetItemCount();
CStringstrSex("男");
if(dlg.m_bMale)strSex="女";
m_ListCtrl.InsertItem(nItem,dlg.m_strNo);
m_ListCtrl.SetItemText(nItem,1,dlg.m_strName);
m_ListCtrl.SetItemText(nItem,2,strSex);
m_ListCtrl.SetItemText(nItem,3,dlg.m_tBirth.Format("%Y-%m-%d"));
m_ListCtrl.SetItemText(nItem,4,dlg.m_strSpecial);
}
③编译运行并测试。
6.实现打印和打印预览
①为CEx_StudentView类添加一个成员变量m_strContents,类型为CStringArray。
用来保存读取列表项的数据。
②为CEx_StudentView类添加一个成员函数ReadListViewData,用于读取列表项的数据,其代码如下:
voidCEx_StudentView:
:
ReadListViewData()
{
m_strContents.RemoveAll();
CListCtrl&m_ListCtrl=GetListCtrl();
intnCount=0;
CHeaderCtrl*pHeaderCtrl=m_ListCtrl.GetHeaderCtrl();
if(pHeaderCtrl!
=NULL)nCount=pHeaderCtrl->GetItemCount();
//读取表头信息作为第一行
LVCOLUMNcolumn;
TCHARlpBuffer[256];
intnWidthCharNum[100];
CStringstr,strTemp;
for(intnCol=0;nColcolumn.mask=LVCF_TEXT;
column.pszText=lpBuffer;
column.cchTextMax=256;
m_ListCtrl.GetColumn(nCol,&column);
nWidthCharNum[nCol]=(int)(m_ListCtrl.GetColumnWidth(nCol)/6.5);
strTemp.Format("%s",lpBuffer);
strTemp.TrimRight();
intnDelta=nWidthCharNum[nCol]-strTemp.GetLength();
if(nDelta>0)strTemp=AppendStringSpace(strTemp,nDelta);
elsestrTemp=strTemp.Left(nWidthCharNum[nCol]);
str=str+strTemp;
}
str.TrimRight();
m_strContents.Add(str);
//读取各个列表项信息
intnItemCount=m_ListCtrl.GetItemCount();
for(intnItem=0;nItemstr.Empty();
strTemp.Empty();
for(inti=0;istrTemp=m_ListCtrl.GetItemText(nItem,i);
strTemp.TrimRight();
intnDelta=nWidthCharNum[i]-strTemp.GetLength();
if(nDelta>0)strTemp=AppendStringSpace(strTemp,nDelta);
elsestrTemp=strTemp.Left(nWidthCharNum[i]);
str=str+strTemp;
}
str.TrimRight();
m_strContents.Add(str);
}
}
③为CEx_StudentView类添加一个成员函数AppendStringSpace,用来在一个字符串后添加空格,其代码如下:
CStringCEx_StudentView:
:
AppendStringSpace(CStringstr,intnNum)
{
for(inti=0;i//通常500大于一个字符串长度,当大于字符串长度,则Insert在字符串末尾添加
returnstr;
}
④打开Ex_StudentView.h文件,在classCEx_StudentView:
publicCListView语句前添加PAGEINFO结构的定义,具体代码如下:
typedefstruct{
CSizesizePage;//页面/纸大小
CSizesizeLine;//每行的大小
CSizesizeChar;//每个字符的平均大小
intnLMargin;//左边距
intnRMargin;//右边距
intnTMargin;//上边距
intnBMargin;//下边距
intnPhyLeft;//物理左边距
intnPhyRight;//物理右边距
intnPhyTop;//物理上边距
intnPhyBottom;//物理下边距
LOGFONTlfHead;//页眉字体
LOGFONTlfFoot;//页脚字体
LOGFONTlfText;//正文字体
}PAGEINFO;//页面信息结构
⑤为CEx_StudentView类添加下列成员变量:
public:
PAGEINFOm_pageInfo;
CStringArraym_arrText;//处理后的文档内容
CUIntArraym_nLineArray;//记录每页的开始行号
⑥为CEx_StudentDoc类增加成员变量public:
boolm_bNewDocument;
为CEx_StudentView类添加成员函数SetPageInfo、PrintHead、PrintFoot和AdjustAllLine,具体代码如下:
voidCEx_StudentView:
:
SetPageInfo(CDC*pDC,CPrintInfo*pInfo,PAGEINFO*pPage,intl,intt,intr,intb,intnLineSpace)
//nLineSpace为行间距,l,t,r,b分别表示左上右下的页边距
{
//计算一个设备单位等于多少0.1mm
doublescaleX=254.0/(double)GetDeviceCaps(pDC->m_hAttribDC,LOGPIXELSX);
doublescaleY=254.0/(double)GetDeviceCaps(pDC->m_hAttribDC,LOGPIXELSY);
intx=GetDeviceCaps(pDC->m_hAttribDC,PHYSICALOFFSETX);
inty=GetDeviceCaps(pDC->m_hAttribDC,PHYSICALOFFSETY);
intw=GetDeviceCaps(pDC->m_hAttribDC,PHYSICALWIDTH);
inth=GetDeviceCaps(pDC->m_hAttribDC,PHYSICALHEIGHT);
intnPageWidth=(int)((double)w*scaleX+0.5);//纸宽,单位0.1mm
intnPageHeight=(int)((double)h*scaleY+0.5);//纸高,单位0.1mm
intnPhyLeft=(int)((double)x*scaleX+0.5);//物理左边距,单位0.1mm
intnPhyTop=(int)((double)y*scaleY+0.5);//物理上边距,单位0.1mm
CRectrcTemp=pInfo->m_rectDraw;
rcTemp.NormalizeRect();
intnPhyRight=nPageWidth-rcTemp.Width()-nPhyLeft;//物理右边距,单位0.1mm
intnPhyBottom=nPageHeight-rcTemp.Height()-nPhyTop;//物理下边距,单位0.1mm
//若边距小于物理边距,则调整它们
if(lif(rpPage->nLMargi