// 签名类成员函数
void CSignal::SetValue(CString signal, CPoint point, COLORREF color,
int escapement, LOGFONT *pfont) {
m_strSignal = signal; m_pointSignal = point; m_colorSignal = color;
memcpy(&m_fontSignal, pfont, sizeof(LOGFONT)); m_fontSignal.lfEscapement = escapement; }
// 显示签名
void CSignal::ShowSignal(CDC *pDC) {
CFont font, *pOldFont;
font.CreateFontIndirect(&m_fontSignal); pOldFont = pDC->SelectObject(&font); pDC->SetTextColor(m_colorSignal); pDC->TextOut(m_pointSignal.x, m_pointSignal.y,
m_strSignal);
pDC->SelectObject(pOldFont); }
// 框架窗口类 #define MAX_NAME 250
class CMyWnd: public CFrameWnd {
CSignal m_signalList[MAX_NAME]; // 签名数组 int m_nCount; // 签名数量
LOGFONT m_fontSignal; // 签名字体 COLORREF m_colorSignal; // 签名颜色 public: CMyWnd(); protected:
afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnRButtonDown(UINT nFlags, CPoint point); afx_msg void OnPaint(); DECLARE_MESSAGE_MAP() };
// 消息映射
BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd) ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_WM_PAINT() END_MESSAGE_MAP() // 框架窗口类的成员函数 CMyWnd::CMyWnd() {
m_nCount = 0;
m_colorSignal = RGB(0, 0, 0); m_fontSignal.lfHeight = 40; m_fontSignal.lfWidth = 0; m_fontSignal.lfEscapement = 0; m_fontSignal.lfOrientation = 0; m_fontSignal.lfWeight = 400; m_fontSignal.lfItalic = FALSE; m_fontSignal.lfUnderline = FALSE; m_fontSignal.lfStrikeOut = 0;
m_fontSignal.lfCharSet = OEM_CHARSET;
m_fontSignal.lfOutPrecision = OUT_DEFAULT_PRECIS; m_fontSignal.lfClipPrecision = CLIP_DEFAULT_PRECIS; m_fontSignal.lfQuality = DEFAULT_QUALITY; m_fontSignal.lfPitchAndFamily = DEFAULT_PITCH; strcpy(m_fontSignal.lfFaceName, \}
// 鼠标右键消息响应函数
void CMyWnd::OnLButtonDown(UINT nFlags, CPoint point) {
if(m_nCount < MAX_NAME) {
CNameDlg dlg;
dlg.m_pointTopLeft = point; if(dlg.DoModal() == IDOK) {
LONG escapement = dlg.m_lEscapement; CString name = dlg.m_strNameEdit; m_signalList[m_nCount].SetValue(name, point,
m_colorSignal,
escapement, &m_fontSignal); m_nCount++; Invalidate(); } } }
// 鼠标右键消息响应函数
void CMyWnd::OnRButtonDown(UINT nFlags, CPoint point) {
CFontDialog dlg(&m_fontSignal); if(dlg.DoModal() == IDOK) {
dlg.GetCurrentFont(&m_fontSignal); m_colorSignal = dlg.GetColor(); } }
// 绘制框架窗口客户区函数 void CMyWnd::OnPaint() {
41 CPaintDC dc(this);
for(int i=0; i // 应用程序类  class CMyApp: public CWinApp { public:  BOOL InitInstance(); };  // 应用程序类的成员函数 BOOL CMyApp::InitInstance() {  CMyWnd *pFrame = new CMyWnd;  pFrame->Create(0,_T(\签字留念簿程序\pFrame->ShowWindow(SW_SHOWMAXIMIZED); this->m_pMainWnd = pFrame; return TRUE; }  // 全局应用程序对象 CMyApp ThisApp;      7-16 为例9-3的吹泡泡程序添加颜色选择对话框,使其可以绘出五颜六色的泡泡。    程 序:在例9-3的程序基础上作如下修改: 1.在程序首部添加文件包含命令: #include  2.在框架窗口类声明中添加一个COLORREF类型的数组,存放各泡泡的颜色:  COLORREF m_colorBubble [MAX_BUBBLE];  3.修改鼠标左键消息映射函数,添加使用颜色选择公用对话框的代码:  void CMyWnd::OnLButtonDown ( UINT nFlags, CPoint point ) {  if(m_nBubbleCount < MAX_BUBBLE) {  m_colorBubble[m_nBubbleCount] = RGB(200, 200, 200); CColorDialog dlg(m_colorBubble[m_nBubbleCount]); if(dlg.DoModal() == IDOK)  m_colorBubble[m_nBubbleCount] = dlg.GetColor(); int r = rand()P+10;  CRect rect(point.x-r, point.y-r, point.x+r, point.y+r); m_rectBubble[m_nBubbleCount] = rect; m_nBubbleCount++;   InvalidateRect(rect, FALSE); } }  4.修改OnPaint()成员函数,添加根据泡泡颜色使用画刷的代码:  void CMyWnd::OnPaint() {  CPaintDC dc(this);  CBrush brushNew, *pbrushOld; for(int i=0; i brushNew.CreateSolidBrush(m_colorBubble[i]); pbrushOld = dc.SelectObject(&brushNew); dc.Ellipse(m_rectBubble[i]); dc.SelectObject(pbrushOld); brushNew.DeleteObject(); } }     7-17 序列化。如果例12-1的吹泡泡程序使用一般的数组存放泡泡数据(参看例9-1的程序): CRect m_rectBubble[MAX_BUBBLE]; int m_nBubbleCount;  为其文档类重新设计Serialize()函数。  说 明:按例12-1的方法建立项目和输入源代码,但将文档类中的泡泡数据改为以上两行的形式。修改文档类的Serialize()函数,代码如下。   程 序: // 序列化函数  void CMyDoc::Serialze(CArchive& ar) {  if(ar.IsStoring()) {  ar << m_nBubbleCount;  for(int i=0; i ar >> m_nBubbleCount;  for(int i=0; i 42     7-18 修改例12-1的程序并观察其打印结果。   程 序:   在例12-1程序的视图类CMyView类的成员函数OnDraw()中,添加代码沿窗口客户区轮廓画一矩形: void CMyView::OnDraw(CDC* pDC) {  CRect rect;  GetClientRect(&rect); pDC->Rectangle(rect);   CMyDoc* pDoc = GetDocument(); // 取文档指针 ASSERT_VALID(pDoc);  pDC->SelectStockObject(LTGRAY_BRUSH); // 在视图上显示文档数据  for(int i=0; i 7-19 改进吹泡泡程序,使之打印输出与屏幕显示的比例相近。   程 序:   在例12-1基础上修改。首先在CMyView类中重载虚函数OnPrepareDC()。在CMyView类的声明中增加一行: virtual  void  OnPrepareDC(CDC  *pDC,  CPrintInfo  *pInfo=NULL);  然后添加该函数的定义,设置映射模式为MM_LOMETRIC: // 设置映射模式  void CMyView::OnPrepareDC(CDC *pDC, CPrintInfo *pInfo) {  pDC->SetMapMode(MM_LOMETRIC); CView::OnPrepareDC(pDC, pInfo); }  然后修改消息映射函数OnLButtonDown(),将物理坐标转换为逻辑坐标:  // 响应点击鼠标左键消息  void CMyView::OnLButtonDown(UINT nFlags, CPoint point) {  CMyDoc* pDoc = GetDocument(); // 取文档指针 ASSERT_VALID(pDoc);  CClientDC dc(this); // 设置设备环境   OnPrepareDC(&dc);  int r = rand()P+5; // 生成泡泡  CRect rect(point.x-r, point.y-r, point.x+r, point.y+r); InvalidateRect(rect, FALSE); // 更新视图 dc.DPtoLP(rect); // 转换物理坐标为逻辑坐标 pDoc->AddBubble(rect); // 修改文档数据 pDoc->SetModifiedFlag(); // 设置修改标志 }    7-20 声明一个Person类,并使之支持序列化。   程 序:  class CPerson: public CObject {  DECLARE_SERIAL( CPerson) LONG m_IDnumber; // 身份证号码 CString m_strName; // 姓名 CString m_strNation; // 民族 int m_nSex; // 性别 int m_nAge; // 年龄 BOOL m_bMarried; // 婚否 public: CEmployee(){};  CPerson& operator = (CPerson& person); void Serialize(CArchive& ar); };  IMPLEMENT_SERIAL( CPerson, CObject, 1 ) CPerson& CPerson::operator = (CPerson& person) {  m_IDnumber = person.m_IDnumber; m_strName = person.m_strName; m_strNation = person.m_strNation; m_nSex = person.m_nSex; m_nAge = person.m_nAge;  m_bMarried = person.m_bMarried; return *this; }  void CPerson::Serialize(CArchive& ar) {  CObject::Serialize( ar); // 首先调用基类的Serialize()方法  if(ar.IsStoring()) {  ar << m_IDnumber; ar << m_strName; ar << m_strNation;  43  ar << m_nSex; ar << m_nAge;  ar << (int)m_bMarried; } else {  ar >> m_IDnumber; ar >> m_strName; ar >> m_strNation; ar >> m_nSex; CFont *pOldFont = (CFont *)(pDC->SelectObject(&font)); CRect rectPaper = pInfo->m_rectDraw; // 取页面打印矩形 // 页眉: 页面顶端中央打印文档名称 CMyDoc *pDoc = GetDocument(); ASSERT_VALID(pDoc); CString str; str.Format(\ (LPCSTR)pDoc->GetTitle());  CSize sizeText = pDC->GetTextExtent(str);  CPoint point((rectPaper.Width()-sizeText.cx)/2, 0); Report:  %s\ ar >> m_nAge;  ar >> (int)m_bMarried; } }   7-21 修改例13-3的吹泡泡程序,使其打印每个泡泡的数据值。打印格式为每页40行,页眉为文档名,页脚为页号。 说 明:首先为视图类添加一个数据成员m_nLinePerPage,用来存放每页行数,并在视图类CMyView的构造函数中将m_nLinePerPage初始化为40。  修改视图类成员函数OnPrepareDC(),设置映射模式为MM_TWIPS。该模式为每英寸1440点,很适合打印机输出。   程 序:   重载视图类的成员函数OnPreparePrinting(),在其中添加计算打印页数的代码:  BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo) {  CMyDoc *pDoc = GetDocument();  int nPageCount = pDoc->GetListSize()/m_nLinePerPage; if(pDoc->GetListSize() % m_nLinePerPage) nPageCount ++;  pInfo->SetMaxPage(nPageCount); return DoPreparePrinting(pInfo); }  最后重载视图类的OnPrint()函数并添加打印代码: void CMyView::OnPrint( CDC* pDC, CPrintInfo* pInfo ) {  int nPage = pInfo->m_nCurPage; // 当前页号  int nStart = (nPage-1)*m_nLinePerPage; // 本页第一行 int nEnd = nStart+m_nLinePerPage; // 本页最后一行 CFont font; // 设置字体  font.CreateFont(-280, 0, 0, 0, 400, FALSE, FALSE,  0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH|FF_MODERN, \  pDC->TextOut(point.x, point.y, str); point.x = rectPaper.left; // 打印页眉下划线 point.y = rectPaper.top-sizeText.cy; pDC->MoveTo(point); point.x = rectPaper.right; pDC->LineTo(point); // 打印表头  str.Format(\\point.x = 720; point.y -= 720;  pDC->TextOut(point.x, point.y, str); TEXTMETRIC tm; // 取当前字体有关信息 pDC->GetTextMetrics(&tm);  int nHeight = tm.tmHeight+tm.tmExternalLeading; point.y -= 360; // 下移 1/4 英寸  for(int i=nStart; i if(i >= pDoc->GetListSize()) break;  str.Format(\pDoc->GetBubble(i).left, pDoc->GetBubble(i).top, pDoc->GetBubble(i).right, pDoc->GetBubble(i).bottom); point.y -= nHeight;  pDC->TextOut(point.x, point.y, str); }  // 在页面底部中央打印页号 str.Format(\sizeText = pDC->GetTextExtent(str);  point.x = (rectPaper.Width()-sizeText.cx)/2; point.y = rectPaper.Height()+sizeText.cy; pDC->TextOut(point.x, point.y, str); // 释放字体对象  pDC->SelectObject(pOldFont); }   44      7-22 修改例11-4的拼图程序,使之在难度菜单的相应选项前打钩。   程 序:   首先在框架窗口类的消息响应函数声明处增加以下消息响应函数的声明: afx_msg void  CPuzzleWnd::OnUpdateGrad01(CCmdUI*  pCmdUI); afx_msg void  CPuzzleWnd::OnUpdateGrad02(CCmdUI*  pCmdUI); afx_msg void  CPuzzleWnd::OnUpdateGrad03(CCmdUI*  pCmdUI);  然后在框架窗口类的消息映射宏中加入相应内容: BEGIN_MESSAGE_MAP(CPuzzleWnd, CFrameWnd) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() ON_WM_PAINT()  ON_COMMAND(ID_SHOWFIG, OnShowFig) ON_COMMAND(ID_GRAD01, OnGrad01) ON_COMMAND(ID_GRAD02, OnGrad02) ON_COMMAND(ID_GRAD03, OnGrad03)  ON_UPDATE_COMMAND_UI(ID_GRAD01, OnUpdateGrad01) ON_UPDATE_COMMAND_UI(ID_GRAD02, OnUpdateGrad02) ON_UPDATE_COMMAND_UI(ID_GRAD03, OnUpdateGrad03) END_MESSAGE_MAP()  注意更新命令用户接口消息映射宏将菜单标识符与相应的消息映射函数联系在一起。最后编写相应的更新命令用户接口消息映射函数:  void CPuzzleWnd::OnUpdateGrad01(CCmdUI* pCmdUI)  {  pCmdUI->SetCheck(m_nColCount == 4); }  void CPuzzleWnd::OnUpdateGrad02(CCmdUI* pCmdUI)  {  pCmdUI->SetCheck(m_nColCount == 8); }  void CPuzzleWnd::OnUpdateGrad03(CCmdUI* pCmdUI)  {  pCmdUI->SetCheck(m_nColCount == 16); }  输入输出:在选择拼图难度时,可在相应选项前打钩(图13-4)。     // Example 13-7: 七巧板程序  ////////////////////////////////// #include  拼 板 类  //////////////////////////////////////////////////// #define MAX_POINTS 4 #define CHIP_WIDTH 240 #define DELTA 30  class CChip : public CObject {  DECLARE_SERIAL(CChip) int m_nType;  CPoint m_pointList[MAX_POINTS]; int m_nPointCount; public: CChip(){}  void SetChip(int type, POINT *ppointlist, int count); void DrawChip(CDC *pDC); BOOL PtInChip(POINT point); LPCRECT GetRect();  void MoveTo(CSize offset); void Rotation();  void Serialize(CArchive &ar); };  IMPLEMENT_SERIAL(CChip, CObject, 1) // 设置拼图块参数  void CChip::SetChip(int type, POINT *ppointlist, int count) {  m_nType = type; m_nPointCount = count; for(int i=0; i // 绘出拼图块  void CChip::DrawChip(CDC *pDC) {  CPen penNew, *ppenOld; CBrush brushNew, *pbrushOld; switch(m_nType) { case 1:   brushNew.CreateSolidBrush(RGB(127, 127, 127)); break; case 2:   brushNew.CreateSolidBrush(RGB(255, 0, 0)); break;  45