Lesson4: 简单绘图

1.       在单文档中view挡在MainFrame的前面。此时如果编写针对MainFramemouseClick

事件,将不会有反应。因为MFC视类窗口是覆盖在框架窗口上的,因此框架窗口不能感

到鼠标消息.

2.       MFC的消息映射机制:

在每个能接收和处理消息的类中,定义一个消息和消息函数对照表,即消息映射表.在消息映射表中,消息与对应的消息处理函数指针成对出现.某个类能处理的所有消息及其对应的消息处理函数的地址都列在这个类所对应的静态表中.当有消息需要处理时,程序只要搜索该消息静态表,查看表中是否含有该消息,就可知道该类能否处理此消息.如果能处理该消息,则同样依照静态表很容易找到并调用对应的消息处理函数.

MFC消息映射机制是针对能接受消息和处理消息的类来定义对应的消息映射表,而不是由父类来定义所有消息对应的虚函数,由子类来覆盖其函数实现,因为这样做会使程序背着一个很大的虚拟函数表的包袱运行,对内存是一种浪费.

MFC工程中一个消息映射在三处添加代码:

(1): CDrawView视类的头文件.h

//{{AFX_MSG(CDrawView)

afx_msg void OnLButtonDown(UINT nFlags, CPoint point);

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

两个AFX_MSG注释宏(因为加了注释符)之间,afx_msg是限定符(也是宏),表明函数是一个消息响应函数的声明,如果是用户自定义的消息函数响应声明则在注释宏下, DECLARE_MESSAGE_MAP之上加写代码

(2): CDrawViewcpp(源文件)BEGIN_MESSAGE_MAPEND_MESSAGE_MAP之间,定义了CDrawView类的消息映射表,其中ON_WM_LBUTTONDOWN映射宏就是将鼠标左键按下消息(WM_LBUTTONDOWN)与一个消息响应函数(OnLButtonDown)关联.

BEGIN_MESSAGE_MAP(CDrawView, CView)

//{{AFX_MSG_MAP(CDrawView)

ON_WM_LBUTTONDOWN()

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)

END_MESSAGE_MAP()

如果添加自定义的消息映射,使用ON_MESSAGE(用户定义消息,消息响应函数名)”;”结尾

(3): CDrawViewcpp(源文件)中有函数实现。

void CDrawView::OnLButtonDown(UINT nFlags, CPoint point)

{

// TOD Add your message handler code here and/or call default

m_ptOrigin=m_ptOld=point;

m_bDraw=TRUE;

CView::OnLButtonDown(nFlags, point);

}

通过分析MFC消息响应函数在程序中有三处属地省:函数原型,用来关联消息和消息响应函数的宏和函数实现.

3.       以下绘图程序,参考代码的注释可解决部分绘图问题

void CLesson3View::OnLButtonUp(UINT nFlags, CPoint point)

{

         // TODO: Add your message handler code here and/or call default

         //作图

         /*调用SDK函数获取设备上下文句柄

         HDC hdc;

         hdc = ::GetDC(m_hWnd);//这个m_hWndCWnd类中的保护成员, 保存窗口句柄,

                        //CLesson3View类是从CWnd类继承来的,所以也有这个成员

         MoveToEx(hdc, m_ptnOrigin.x, m_ptnOrigin.y, NULL);

         LineTo(hdc, point.x, point.y);

         ::ReleaseDC(m_hWnd, hdc); // 在使用完设备上下文句柄后一定注意释放*/

 

         /*使用CDC(MFC)关于作图对HDC一个封装*/

//      CDC *pDc;

//      pDc = GetDC();

//      pDc->MoveTo(m_ptnOrigin);

//      pDc->LineTo(point);

//      ReleaseDC(pDc);

 

         /*使用客户区绘图类,这个是比较常用的*/

         //CClientDC dc(this);//CClientDC的构造函数,使用当前窗口句柄值做为参数

         //CClientDC dc(GetParent());//得到关于父类窗口一个设备上下文

//      dc.MoveTo(m_ptnOrigin);

//      dc.LineTo(point);

         // CClientDC类在构造时调用GetDC,然后在释放时又调用ReleaseDC所以不用手动释放

   

     //利用MFCCWindowDC绘图

/好处是可以访问整个窗口区域,包括框架窗口客户区和非客户区,桌面等,

//       CWindowDC dc(this);

//      CWindowDC dc(GetParent());

//      dc.MoveTo(m_ptnOrigin);

//      dc.LineTo(point);

//      CWindowDC dc(GetDesktopWindow());//这个可以画到桌面上其它地方

//      dc.MoveTo(m_ptnOrigin);

//      dc.LineTo(point);

         //以上所画的线条颜色都是黑色的,因为在设备描述表中使用默认的画笔(黑色),

         //要改变线条颜色则需要自己生成一个新的画笔对象,

//将它选到设备描述表中,再画就使用新画笔来绘图

//      CPen m_pen(PS_DASH, 2, RGB(255, 0, 0));//生成新的画笔

//      CClientDC dc(this);

//      CPen *pOldPen = dc.SelectObject(&m_pen);//选择进设备描述表中

//      dc.MoveTo(m_ptnOrigin);

//      dc.LineTo(point);

//      dc.SelectObject(pOldPen);//在使用完新的画笔后,要将原来的画笔重新选择时设备描述表

         //使用画刷来填充矩形

//      CBrush m_brush(RGB(120, 0, 23));

//      CClientDC dc(this);

//      dc.FillRect(CRect(m_ptnOrigin, point), &m_brush);

         //使用位图画刷来填充矩形

         //创建一个位图对象

//      CBitmap m_bitmap;

//      m_bitmap.LoadBitmap(IDB_MyBitmap);

//      CBrush m_Brush(&m_bitmap);

//      CClientDC dc(this);

//      dc.FillRect(CRect(m_ptnOrigin, point), &m_Brush);

         //透明画刷

         //首先使用Win32API函数GetStockObject来获取一个NULL_BRUSH画刷

         CClientDC dc(this);

         CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));

                //是静态成员函数,从句柄获取对象的指针

         CBrush *pOldBrush = dc.SelectObject(pBrush);

         dc.Rectangle(CRect(m_ptnOrigin, point));

         dc.SelectObject(pOldBrush);

         bIsMouseDown = FALSE;

         CView::OnLButtonUp(nFlags, point);

}

类的静态成员函数可以由类名直接调用,也可以由对象调用。可以认为静态成员函数并不 属于某个对象,它属于类本身。程序运行伊始,即使没有实例化类的对象,静态成员函数和静态成员变量已然有其内存空间。静态成员函数不能访问非静态成员变 量!静态成员变量必须在类的外部初始化。当然如果并不打算用到静态成员变量,此时你可以不初始它。

4.       理解代码区,数据区,堆,栈!(http://www.cnblogs.com/gaojun/admin/(http://www.downcode.com/server/j_server/J_1010.Html)

对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)” 是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干 扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址 和偏移量来访问本地变量。

 

 

 

 

Lesson5: 文本编程

1,创建插入符:

void CreateSolidCaret( int nWidth, int nHeight );//创建插入符

void CreateCaret( CBitmap* pBitmap );//创建位图插入符

void ShowCaret( );//显示插入符

void HideCaret( );//隐藏插入符

static void PASCAL SetCaretPos( POINT point );//移动插入符号

说明:

1)创建插入符要在窗口创建完成之后,CreateSolidCaret函数创建的插入符被初始化为隐藏,所以需要调用ShowCaret()将其显示。

2)使用CreateCaret函数创建位图插入符的时候,不能使用局部的位图对象关联位图资源。(与资源相关联的C++对象,当它析构的时候会同时把与它相关联的资源销毁。)

2,获取当前字体信息的度量:CDC::GetTextMetrics

BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;

说明:

typedef struct tagTEXTMETRIC { /* tm */

    int tmHeight;//字体高度。Specifies the height (ascent + descent) of characters.

    int tmAscent;//基线以上的字体高度

    int tmDescent;//基线以下的字体高度

    int tmInternalLeading;

    int tmExternalLeading;

    int tmAveCharWidth;//字符平均宽度

    int tmMaxCharWidth;

    int tmWeight;

    BYTE tmItalic;

    BYTE tmUnderlined;

    BYTE tmStruckOut;

    BYTE tmFirstChar;

    BYTE tmLastChar;

    BYTE tmDefaultChar;

    BYTE tmBreakChar;

    BYTE tmPitchAndFamily;

    BYTE tmCharSet;

    int tmOverhang;

    int tmDigitizedAspectX;

    int tmDigitizedAspectY;

} TEXTMETRIC;

//创建设备描述表

       CClientDC dc(this);

       //定义文本信息结构体变量

       TEXTMETRIC tm;

       //获得设备描述表中的文本信息

       dc.GetTextMetrics(&tm);

       //根据字体大小,创建合适的插入符

       CreateSolidCaret(tm.tmAveCharWidth / 8, tm.tmHeight);

       ShowCaret();

3OnDraw函数:

virtual void OnDraw( CDC* pDC )

当窗口(从无到有或尺寸大小改变等)要求重绘的时候,会发送WM_PAIN消息,调用OnDraw函数进行重绘。在客户区的绘图如果想保持不变也可以在这个函数中进行编写,每次重给的时候会再次执行代码,生成绘图.

4,获取某字符串的高度和宽度(区别字符串的长度,长度表示字符个数):

CDC::GetTextExtent

CSize GetTextExtent( LPCTSTR lpszString, int nCount ) const;

CSize GetTextExtent( const CString& str ) const;

说明:

//The CSize class is similar to the Windows SIZE structure

typedef struct tagSIZE {

    int cx;//the x-extent

    int cy;//the y-extent

} SIZE;

 

5,路径层:

BOOL BeginPath( );//CDC中函数

//在这作图定义路径层剪切区域

BOOL EndPath( );

BOOL SelectClipPath( int nMode );//调用这个函数来使当前路径层剪切区域与新剪切区域进行互操作。  

//在这覆盖作图(包含前定义的路径层区域)定义新的剪切区域

说明:

1SelectClipPath Selects the current path as a clipping region for the device context, combining the new region with any existing clipping region by using the specified mode. The device context identified must contain a closed path.

2)应用:当作图的时候,如果想要在整幅图形其中的某个部分和其它部分有所区别,我们可以把这部分图形放到路径层当中,然后指定调用指定互操作模式调用SelectClipPath( int nMode )函数来使路径层和覆盖在其上新绘图剪切区域进行互操作,达到特殊效果。

6,关于文本字符串一些函数:

COLORREF GetBkColor( ) const;//得到背景颜色

virtual COLORREF SetBkColor( COLORREF crColor );//设置背景颜色

BOOL SetTextBkColor( COLORREF cr );//设置文本背景颜色

virtual COLORREF SetTextColor( COLORREF crColor );//设置文本颜色

virtual BOOL TextOut( int x, int y, LPCTSTR lpszString, int nCount );//输出文本

BOOL TextOut( int x, int y, const CString& str );//x,y所指定坐标处输出str

CString Left( int nCount ) const;//得到字符串左边nCount个字符

int GetLength( ) const;//得到字符串长度strlen()

7,字体CFont::CFont

CFont( );//构造函数

//Constructs a CFont object. The resulting object must be initialized with CreateFont, CreateFontIndirect, CreatePointFont, or CreatePointFontIndirect before it can be used.

选用字体事例代码组:

CClientDC dc(this);

CFont font;//构造字体对象

font.CreatePointFont(300,"华文行楷",NULL);//初始化字体对象,与字体资源相关联

CFont *pOldFont=dc.SelectObject(&font);//将新字体选入DC

...

dc.SelectObject(pOldFont);//恢复原字体

说明:

1)构造字体对象时候,必须初始化。(初始化是将字体对象与字体资源相关联)。

2)初始化对象时候,选用的字体也可以是系统字体,但不一定都有效,据测试选用。

8,在MFCCEditView cRichEditView类已经完成了初步的文字处理。可以让应用程序的View类以CEditView cRichEditView类为基类。在创建工程中的第六步可以选择.

9,平滑变色

CDC::TextOut()是一个字母一个字母的输出,达不到平滑效果。

CDC::DrawText():将文字的输出局限于一个矩形区域,超出矩形区域的文字都被截断。利用这一特点,可每隔些时间增加矩形大小,从而可实现人眼中的平滑效果。

CWnd::SetTimer():设置定时器。按设定的时间定时发送WM_TIMER消息。

说明:

UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );

//nIDEvent定时器标示,nElapse消息发送间隔时间,void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD)设置回调函数,如果设置则由设置的回调函数处理WM_TIMER消息,如果没有设置回调函数设为NULL,这发送的WM_TIMER消息压入消息队列,交由相关联的窗口处理(添加WM_TIMER消息处理函数OnTimer())。

afx_msg void OnTimer( UINT nIDEvent );

//响应WM_TIMER消息,nIDEvent为消息对应定时器标示(可以设置不同的定时器发送WM_TIMER消息)

 

问题:

1,在CCareView类中添加WM_CREATE消息响应函数OnCreate(),WM_CREATE消息是在什么时候被检查到而被响应的呢?

(猜测:添加WM_CREATE消息后,消息被压入消息队列,然后经过消息循环进行分发到具体窗口,从而进行响应)

2,现有一文本文件内容已经读入串STR中,要求在视图客户区按原先文本文件中的格式输出。

问题是,利用CDCTextOut()来在CView类派生类窗口中输出串时,忽略了串中的TAB、回车换行等格式,无论串有多长均在一行上输出。

这其中是CDC类成员函数TextOut()忽略串中格式的,还是CView类派生类窗口设置从中做怪呢?怎么解决

 

 

 

 

Lesson6: 菜单编程

1.       MFC中的顶层菜单默认为弹出菜单(Pop-up),它是不能用来作命令响应的,当取消Pop-up选项后可接受命令响应。

2.       消息的分类:标准消息,命令消息,通告消息。

[标准消息]:除WM_COMMAND之外,所有以WM_开头的消息。从CWnd类派生的类都可以接收到这一消息

[命令消息]:来自菜单、加速键或工具栏按钮的消息。这类消息都以WM_COMMAND呈现。在MFC中,通过菜单项的标识(ID)来区分不同的命令消息;在SDK中,通过消息的wParam参数识别。从CCmdTargetCWnd的父类)派生的类都可以接收到这一类消息

[通告消息]:由控件产生的消息,例如,按钮的单击,列表框的选择等均产生此类消息,为的是向其父窗口(通常是对话框)通知事件的发生。这类消息也是以WM_COMMAND形式呈现。从CCmdTargetCWnd的父类)派生的类都可以接收到这一类消息

总结:凡是从CWnd派生的类,既可以接收标准消息,也要以接收命令消息和通告消息。而对于那些从CCmdTarget派生的类,则只能接收命令消息和通告消息,不能接收标准消息。

3.       MFC中菜单项消息如果利用ClassWizard来对菜单项消息分别在上述四个类中进行响应,则菜单消息传递顺序:View--Doc--CMainFrame--App类。菜单消息一旦在其中一个类中响应则不再在其它类中查找响应函数。

菜单消息与前面介绍的标准消息的实现机制是相类似的,都是在消息响应函数原型(头文件),消息映射宏(源文件)和消息函数实现(源文件)中添加代码。注意:文档类与应用程序类都是由CCmndTarget类派生,所以可以接收菜单命令消息,但不能接收标准消息(只能由CWnd类派生才可以)。

具体消息路由过程:

当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类,CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终交给App类进行处理。

4.       一个菜单栏可以有若干个子菜单,一个子菜单又可以有若干个菜单项等。对菜单栏的子菜单由左至右建立从0开始的索引。对特定子菜单的菜单项由上至下建立了从0开始的索引。访问子菜单和菜单项均可以通过其索引或标识(如果有标识的话)进行。

相关重要函数:

CMenu* GetMenu( ) ;//CWnd::GetMenu得到窗口菜单栏对象指针。

CMenu* GetSubMenu( ) ;//CMenu::GetSubMenu获得指向弹出菜单对象指针

UINT CheckMenuItem( );//CMenu::CheckMenuItem 添加选中标识

BOOL SetDefaultItem();//CMenu::SetDefaultItem 为指定菜单设置缺省菜单项

BOOL SetMenuItemBitmaps( );//CMenu::SetMenuItemBitmaps 设置位图标题菜单。

UINT EnableMenuItem();//CMenu::EnableMenuItem使菜单项有效,无效,或变灰。

BOOL SetMenu( CMenu* pMenu );//CWnd::SetMenu在当前窗口上设置新菜单或移除菜单。

HMENU Detach( );//CMenu::Detach;断开一个菜单资源与相关的类对象句柄关联,可以定义局部对象,在使用完后调用Detach函数,则不会因为局部对象影响使用

说明:

1)在计算子菜单菜单项的索引的时候,分隔栏符也算索引的。

2int GetSystemMetrics()获取系统信息度量。可以用它来获取菜单标题的尺寸(后面还会使用到获取屏目尺寸)从而设置位图标题菜单中位图的大小。

3)在MFCMFC为我们提供了一套命令更新机制,所有菜单项的更新都是由这套机制来完成的。所以要想利用CMenu::EnableMenuItem来自己控制菜单使用或不使用变灰等,必须要在CMainFrame的构造函数中将变量m_bAutoMenuEnable设置为FALSE

EXAMPLE

CMenu menu;//定义为局部对象

menu.LoadMenu(IDR_MAINFRAME);

SetMenu(&menu);

menu.Detach();// 这里menu对象作为一个局部对象。使用Detach()menu对象中分离窗口菜单句柄,从而当menu对象析构的时候窗口菜单资源不随之销毁。

5.       命令更新机制:

菜单项状态的维护是依赖于CN_UPDATE_COMMAND_UI消息,谁捕获CN_UPDATE_COMMAND_UI消息,MFC就在其中创建一个CCmdUI对象。

在后台操作系统发出WM_INITMENUPOPUP消息,然后由MFC的基类如CFrameWnd接管并创建一个CCmdUI对象和第一个菜单项相关联,调用对象成员函数DoUpdate()(注:这个函数在MSDN中没有找到说明)发出CN_UPDATE_COMMAND_UI消息,这条消息带有指向CCmdUI对象的指针。此后同一个CCmdUI对象又设置为与第二个菜单项相关联,这样顺序进行,直到完成所有菜单项。

更新命令UI处理程序仅应用于弹出式菜单项上的项目,不能应用于永久显示的顶级菜单项目。

说明:

1)可以手工或用ClassWizard来给菜单项添加UPDATE_COMMAND_UI消息响应,利用响应函数中传进来的CCmdUI对象指针可完成设置菜单项可使用,不可使用,变灰,设置标记菜单等操作。

 

6,如果要想让工具栏上的某个图标与菜单项的某个菜单相关联,只需要将图标的ID设置为该菜单项的ID

工具栏图标的索引记数顺序是:从做至右从0开始,分隔符也算索引号。

 

7,利用向项目中添加VCPOPMENU控件:Project->Add to Project->Components and Controls..

系统增加的内容:A,一个菜单资源;B,在派生View类中增加了OnContextMenu()函数

说明:

1CWnd::OnContextMenu Called by the framework when the user has clicked the right mouse button (right clicked) in the window. You can process this message by displaying a context menu using the TrackPopupMenu.

2BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL );

//CMenu::TrackPopupMenu Displays a floating pop-up menu at the specified location and tracks the selection of items on the pop-up menu. A floating pop-up menu can appear anywhere on the screen.

 

8,利用调用TrackPopupMenu函数,手工添加弹出菜单:

1)用资源管理器添加一个菜单资源

2)在鼠标右键消息响应函数中,加载菜单资源,并获得要显示的子菜单指针,并用该指针调用TrackPopupMenu函数便完成任务(但要注意:鼠标响应函数传进来的坐标是客户区坐标,而TrackPopupMenu函数中使用的是屏幕坐标,在调用TrackPopupMenu前要调用ClientToScreen客户区坐标到屏幕坐标的转换)

事例代码:

CMenu menu;

menu.LoadMenu(IDR_MENU1);

CMenu *pPopup=menu.GetSubMenu(0);

ClientToScreen(&point);

pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,this);

说明:

CWnd::ClientToScreen(..);//将一个坐标点或一个矩形区域坐标转换成屏幕坐标。

CMenu::TrackPopupMenu(..);//在指定位置以指定的方式显示弹出菜单。

CWnd::ScreenToClient(..);

//Converts the screen coordinates of a given point or rectangle on the display to client coordinates.

 

9,当弹出菜单属于框架窗口的时候(可在TrackPopupMenu函数参数中设置),弹出菜单上的消息,在路由的时候,仍然遵循View-DOC-MainFrame-APP的响应顺序。

 

10,动态菜单编程:

所有的资源对象都有一个数据成员保存了资源的句柄。

CMenu::AppendMenu //Appends a new item to the end of a menu.

CMenu::CreatePopupMenu //Creates an empty pop-up menu and attaches it to a CMenu object.

CMenu::InsertMenu

//Inserts a new menu item at the position specified by nPosition and moves other items down the menu.

CMenu::GetSubMenu //Retrieves a pointer to a pop-up menu.

CWnd::GetMenu //Retrieves a pointer to the menu for this window.

CMenu::DeleteMenu //Deletes an item from the menu.

 

11,手动给动态菜单项添加响应函数:

Resource.h中可以添加资源的ID

在头文件中写消息函数原型

在代码文件中添加消息映射和添加消息响应函数

说明:

可以先创建一个临时的菜单项,设置它的ID和动态菜单项的一致,然后对它用向导进行消息响应,然后删除临时菜单。

再在代码文件中把消息映射放到宏外(注意一定要放到宏外面,因为CLASSWIZARD发现菜单删除了,同时要把其宏对里的消息映射也删除掉的)

 

12CWnd::DrawMenuBar

//Redraws the menu bar. If a menu bar is changed after Windows has created the window, call this function to draw the changed menu bar

 

CWnd::GetParent //get a pointer to a child window’s parent window (if any).

CWnd::Invalidate //注意其参数的作用

 

13,集合类:

CStringArrayCStringArrayCDWordArrayCPtrArrayCStringArrayCUIntArrayCWordArray

其中成员函数:

CArray::GetAt

CArray::Add

 

14,命令消息是到OnCommand函数的时候完成路由的。

由于CWnd::OnCommand 是个虚函数,可以在框架类中重写OnCommand函数,从而可以截获菜单消息使它不再往下(VIEW类)路由。

例:

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam)

{

 // TODO: Add your specialized code here and/or call the base class

 int MenuCmdId=LOWORD(wParam);//取命令ID

 CMenu2View *pView=(CMenu2View*)GetActiveView();//获取当前VIEW类指针

 if(MenuCmdId>=IDM_PHONE1 && MenuCmdId<IDM_PHONE1+pView->m_strArray.GetSize())//消息范围判断

 {

 CClientDC dc(pView);

 dc.TextOut(0,0,pView->m_strArray.GetAt(MenuCmdId-IDM_PHONE1));

 return TRUE;

   //函数返回,避免调用CFrameWnd::OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理

 }

 return CFrameWnd::OnCommand(wParam, lParam);

 //调用基类OnCommand函数,在CFrameWnd::OnCommand中截获的消息会交由VIEW类处理

}

 

15LOWORDHIWORD

WORD LOWORD(

 DWORD dwValue // value from which low-order word is retrieved

);

WORD HIWORD(

 DWORD dwValue // value from which high-order word is retrieved

);

 

//The LOWORD macro retrieves the low-order word from the given 32-bit value.

//The HIWORD macro retrieves the high-order word from the given 32-bit value.

 

16CFrameWnd::GetActiveView

CView* GetActiveView( ) const;//获取当前视窗口指针(单文档框架中)

源文件是单独参与编译的。