MFC入门(一)

Windows消息机制

基本概念解释

1) SDK和API

SDK: 软件开发工具包(Software Development Kit),一般都是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件的开发工具的集合。

API函数: Windows操作系统提供给应用程序编程的接口(Application Programming Interface)。

                 Windows应用程序API函数是通过C语言实现的,所有主要的 Windows 函数都在 Windows.h 头文件中进行了声明。Windows 操作系统提供了 1000 多种 API函数。

 

2) 窗口和句柄

窗口是 Windows 应用程序中一个非常重要的元素,一个 Windows 应用程序至少要有一个窗口,称为主窗口。

窗口是屏幕上的一块矩形区域,是 Windows 应用程序与用户进行交互的接口。利用窗口可以接收用户的输入、以及显示输出。

一个应用程序窗口通常都包含标题栏、菜单栏、系统菜单、最小化框、最大化框、 可调边框,有的还有滚动条。如下图:

窗口可以分为客户区和非客户区, 如上图。 客户区是窗口的一部分, 应用程序通常在客户区中显示文字或者绘制图形。

标题栏、 菜单栏、 系统菜单、 最小化框和最大化框、 可调边框统称为窗口的非客户区, 它们由 Windows 系统来管理, 而应用程序则主要管理客户区的外观及操作。

窗口可以有一个父窗口, 有父窗口的窗口称为子窗口。除了上图所示类型的窗口外, 对话框和消息框也是一种窗口。 在对话框上通常还包含许多子窗口, 这些子窗口的形式有按钮、 单选按钮、 复选框、 组框、 文本编辑框等。

 

在 Windows 应用程序中, 窗口是通过窗口句柄( HWND) 来标识的。 我们要对某个窗口进行操作, 首先就要得到这个窗口的句柄。

 

句柄( HANDLE) 是 Windows 程序中一个重要的概念, 使用也非常频繁。 在 Windows 程序中, 有各种各样的资源( 窗口、 图标、光标,画刷等), 系统在创建这些资源时会为它们分配内存, 并返回标识这些资源的标识号, 即句柄。

在后面的内容中我们还会看到图标句柄( HICON)、 光标句柄( HCURSOR) 和画刷句柄( HBRUSH)。

 

3) 消息与消息队列

Windows 程序设计是一种完全不同于传统的 DOS 方式的程序设计方法。它是一种事件驱动方式的程序设计模式,主要是基于消息的。

每一个 Windows 应用程序开始执行后, 系统都会为该程序创建一个消息队列, 这个消息队列用来存放该程序创建的窗口的消息。

例如,当用户在窗口中画图的时候,按下鼠标左键,此时,操作系统会感知到这一事件,于是将这个事件包装成一个消息,投递到应用程序的消息队列中,等待应用程序的处理。

然后应用程序通过一个消息循环不断地从消息队列中取出消息,并进行响应。

在这个处理过程中,操作系统也会给应用程序“ 发送消息”。所谓“ 发送消息”,实际上是操作系统调用程序中一个专门负责处理消息的函数,这个函数称为窗口过程。

 

 鼠标操作窗口时,操作系统先捕获到消息,把消息放到消息队列中,应用程序捕获消息GetMessage(),然后DispatchMessage()分发消息给操作系统,操作系统调用回调函数----窗口过程

 

 

4) WinMain函数

当Windows操作系统启动一个程序时,它调用的就是该程序的WinMain函数( 实际是由插入到可执行文件中的启动代码调用的)。

WinMain是Windows程序的入口点函数,与DOS程序的入口点函数main的作用相同,当WinMain 函数结束或返回时,Windows应用程序结束。

 

 Windows 编程模型

一个完整的Win32程序(#include <windows.h>),该程序实现的功能是创建一个窗口,并在该窗口中响应键盘及鼠标消息,程序的实现步骤为:

1) WinMain函数的定义

2) 创建一个窗口

3) 进行消息循环

4) 编写窗口过程函数

 

1) WinMain函数的定义

int WINAPI WinMain(

                         HINSTANCE hInstance, //应用程序实例

                         HINSTANCE hPrevInstance, //上一个应用程序实例

                         LPSTR lpCmdLine, //命令行参数

                         int nShowCmd); //窗口显示的样式

                   );

WINAPI:是一个宏,它代表的是__stdcall(注意是两个下划线)

                表示的是参数传递的顺序:从右往左依次入栈,同时在函数返回前自动清空堆栈

hInstance:表示该程序当前运行的实例的句柄,这是一个数值。当程序在Windows下运行时,它唯一标识运行中的实例(注意,只有运行中的程序实例, 才有实例句柄)。一个应用程序可以运行多个实例,每运行一个实例,系统都会给该实例分配一个句柄值,并通过hInstance参数传递给                           WinMain 函数。

hPrevInstance:表示当前实例的前一个实例的句柄。在Win32环境下,这个参数总是NULL,即在Win32环境下,这个参数不再起作用。

lpCmdLine:是一个以空终止的字符串, 指定传递给应用程序的命令行参数,相当于C或C++中的main函数中的参数char *argv[]。

nShowCmd:表示一个窗口的显示,表示它是要最大化显示、最小化显示、正常大小显示还是隐藏显示。

 

2) 创建一个窗口

创建一个完整的窗口,需要经过下面几个步骤:

1. 设计一个窗口类

    一个完整的窗口具有许多特征, 包括光标(鼠标进入该窗口时的形状)、图标、背景色等。窗口的创建过程类似于汽车的制造过程。

    我们在生产一个型号的汽车之前, 首先要对该型号的汽车进行设计, 在图纸上画出汽车的结构图, 设计各个零部件, 同时还要给该型号的汽车取一个响亮的名字, 例如“宝马 x6”。

    类似地, 在创建一个窗口前, 也必须对该类型的窗口进行设计, 指定窗口的特征。

    在Windows中,窗口的特征就是由WNDCLASS结构体来定义的,我们只需给WNDCLASS结构体对应的成员赋值,即可完成窗口类的设计。

 

WNDCLASS结构体的定义如下:

typedef struct _WNDCLASS{
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
} WNDCLASS;

style:指定窗口的样式(风格),常用的样式如下:

类型

含义

CS_HREDRAW

当窗口水平方向上的宽度发生变化时, 将重新绘制整个窗口。 当窗口发生重绘时, 窗口中的文字和图形将被擦除。如果没有指定这一样式,那么在水平方向上调整窗口宽度时,将不会重绘窗口。

CS_VREDRAW

当窗口垂直方向上的高度发生变化时,将重新绘制整个窗口。如果没有指定这一样式,那么在垂直方向上调整窗口高度时,将不会重绘窗口。

CS_NOCLOSE

禁用系统菜单的 Close 命令,这将导致窗口没有关闭按钮。

CS_DBLCLKS

当用户在窗口中双击鼠标时,向窗口过程发送鼠标双击消息。

lpfnWndProc:指定一个窗口回调函数,是一个函数的指针。

当应用程序收到给某一窗口的消息时,就应该调用某一函数来处理这条消息。这一调用过程不用应用程序自己来实施,而由操作系统来完成,但是,回调函数本身的代码必须由应用程序自己完成。

对于一条消息,操作系统调用的是接受消息的窗口所属的类型中的lpfnWndProc成员指定的函数。每一种不同类型的窗口都有自己专用的回调函数,该函数就是通过lpfnWndProc成员指定的。

回调函数的定义形式如下:

LRESULT CALLBACK WindowProc(
    HWND hWnd,        //信息所属的窗口句柄
    UINT uMsg,        //消息类型
    WPARAM wParam,    //附加信息(如键盘哪个键按下)
    LPARAM lParam    //附加信息(如鼠标点击坐标)
    );

cbClsExtra:类的附加内存,通常数情况下为0。

cbWndExtra:窗口附加内存,通常情况下为0。

hInstance:当前实例句柄,用WinMain中的形参hInstance为其赋值。

hIcon:指定窗口类的图标句柄,设置为NULL,则使用默认图标,也可用如下函数进行赋值:

HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
如:LoadIcon(NULL, IDI_WARNING); //第一个参数为NULL,加载系统默认图标

hCursor:指定窗口类的光标句柄,设置为NULL,则使用默认图标,也可用如下函数进行赋值:

HCURSOR LoadCursor(HINSTANCE hInstance, LPCTSTR lpCursorName);
如:LoadCursor(NULL, IDC_HELP); //第一个参数为NULL,加载系统默认光标

hbrBackground:指示窗口的背景颜色,可用如下函数进行赋值:

HGDIOBJ GetStockObject(int fnObject);
如:GetStockObject(WHITE_BRUSH);

lpszMenuName:指定菜单资源的名字。如果设置为NULL,那么基于这个窗口类创建的窗口将没有默认菜单。

lpszClassName:指定窗口类的名字。

2. 注册窗口类

设计完窗口类(WNDCLASS)后, 需要调用RegisterClass函数对其进行注册,注册成功后,才可以创建该类型的窗口。

注册函数的原型声明如下:

ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

使用示例:RegisterClass(&wc);

3. 创建窗口

设计好窗口类并且将其成功注册之后, 即可用CreateWindow函数产生这种类型的窗口了。 

CreateWindow函数的原型声明如下:

HWND CreateWindow(
        LPCTSTR lpClassName,
        LPCTSTR lpWindowName,
        DWORD dwStyle,
        int x,
        int y,
        int nWidth,
        int nHeight,
        HWND hWndParent,
        HMENU hMenu,
        HINSTANCE hInstance,
        LPVOID lpParam
);

参数说明:

lpClassName:指定窗口类的名称,此名字必须和WNDCLASS的lpszClassName成员指定的名称一样。

lpWindowName:指定窗口的名字,即窗口的标题。

dwStyle:指定创建的窗口的样式,常指定为指WS_OVERLAPPEDWINDOW类型,这是一种多种窗口类型的组合类型。

xy:指定窗口左上角的x,y坐标。如果参数x被设为CW_USEDEFAULT,那么系统为窗口选择默认的左上角坐标并忽略y参数。

nWidthnHeight:指定窗口窗口的宽度,高度。如果参数nWidth被设为 CW_USEDEFAULT,那么系统为窗口选择默认的宽度和高度,参数nHeight被忽略。

hWndParent:指定被创建窗口的父窗口句柄,没有父窗口,则设置NULL。

hMenu:指定窗口菜单的句柄,没有,则设置为NULL。

hInstance:窗口所属的应用程序实例的句柄,用WinMain中的形参hInstance为其赋值。

lpParam:作为WM_CREATE消息的附加参数lParam传入的数据指针。通常设置为NULL。

返回值说明:如果窗口创建成功,CreateWindow函数将返回系统为该窗口分配的句柄,否则,返回NULL。

示例代码:

HWND  hWnd = CreateWindow(
TEXT("MyWin"),  //窗口类名字
TEXT("测试"),      //窗口标题
WS_OVERLAPPEDWINDOW,  //窗口风格    
CW_USEDEFAULT, CW_USEDEFAULT,  //窗口x,y坐标,使用默认值
CW_USEDEFAULT, CW_USEDEFAULT,  //窗口宽度,高度,使用默认值
NULL,      //无父窗口
NULL,     //无菜单
hInstance,     //应用程序实例句柄,为WinMain第1个形参
NULL);    //附件信息,通常设置为NULL

4. 显示及更新窗口

显示窗口函数原型:

BOOL ShowWindow(HWND hWnd, int nCmdShow);

更新窗口函数原型:

BOOL UpdateWindow(HWND hWnd);

示例代码:

ShowWindow(hWnd, SW_SHOWNORMAL); //SW_SHOWNORMAL为普通模式
UpdateWindow(hWnd);

5. 通过循环取消息

6. 处理消息(窗口过程)

在完成上述步骤后,剩下的工作就是编写一个窗口过程函数,用于处理发送给窗口的消息。

窗口过程函数的名字可以随便取, 如WinProc, 但函数定义的形式必须和下面声明的形式相同:

//CALLBACK __stdcall 参数的传递顺序,从右到左,依次入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
     HWND hwnd,//消息所属的窗口句柄
     UINT uMsg,//具体的消息名称 WM__XXX消息名
     WPARAM wParam,//键盘的附加消息
     LPARAM lParam//鼠标的附加消息
    )

DefWindowProc函数:DefWindowProc函数调用默认的窗口过程,对应用程序没有处理的其他消息提供默认处理。

WM_CLOSE:对WM_CLOSE消息的响应并不是必须的,如果应用程序没有对该消息进行响应,系统将把这条消息传给DefWindowProc函数而 DefWindowProc函数则调用DestroyWindow函数来响应这条WM_CLOSE消息。

WM_DESTROY:DestroyWindow函数在销毁窗口后,会给窗口过程发送 WM_DESTROY消息,我们在该消息的响应代码中调用PostQuitMessage函数。

PostQuitMessage函数向应用程序的消息队列中投递一条WM_QUIT消息并返回。

WinMain函数中,GetMessage 函数只有在收到WM_QUIT消息时才返回0,此时消息循环才结束,程序退出。传递给 PostQuitMessage函数的参数值将作为WM_QUIT消息的wParam参数,这个值通常用做WinMain函数的返回值。

//处理窗口过程
//CALLBACK __stdcall 参数的传递顺序,从右到左,依次入栈,并且在函数返回前清空堆栈
LRESULT CALLBACK WindowProc(
     HWND hwnd,//消息所属的窗口句柄
     UINT uMsg,//具体的消息名称 WM__XXX消息名
     WPARAM wParam,//键盘的附加消息
     LPARAM lParam//鼠标的附加消息
    )
{
    switch(uMsg)
    {

    case WM_CLOSE:
//所有xxxWindow为结尾的方法,都不会进入消息队列中,而是直接执行 DestroyWindow(hwnd);//DestroyWindow发送另一个消息 WM_DESTROY break; case WM_DESTROY: PostQuitMessage(0); break; case WM_LBUTTONDOWN://鼠标左键按下 { int xPos=LOWORD(lParam); int yPos=HIWORD(lParam); char buf[1024]; wsprintf((LPWSTR)buf,TEXT("x=%d,y=%d"),xPos,yPos); MessageBox(hwnd,buf,TEXT("点击"),MB_OK); break; } case WM_KEYDOWN://键盘 MessageBox(hwnd,TEXT("键盘按下"),TEXT("键盘按下"),MB_OK); break; case WM_PAINT://绘图 { PAINTSTRUCT ps;//绘图结构体 HDC hdc=BeginPaint(hwnd,&ps); TextOut(hdc,100,100,TEXT("hello world!"),strlen("hello world!")); EndPaint(hwnd,&ps); } break; } //返回值用默认处理方式 return DefWindowProc(hwnd,uMsg,wParam,lParam); }

 

#include<Windows.h>//底层实现窗口的头文件

int WINAPI WinMain(
    HINSTANCE hInstance,//应用程序实例句柄 
    HINSTANCE hPrevInstance,//上一个应用程序句柄,在win32环境下,参数一般为NULL,不起作用了
    LPSTR lpCmdLine,
    int nShowCmd
    )
{
    //1. 设计窗口
    WNDCLASS wc;
    HWND hwnd;
    MSG msg;
    wc.cbClsExtra=0;//类的额外的内存
    wc.cbWndExtra=0;//窗口的额外内存
    wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);//设置背景
    wc.hCursor=LoadCursor(NULL,IDC_HAND);//设置光标,如果第一个参数为NULL,代表使用系统提供的光标
    wc.hIcon=LoadIcon(NULL,IDI_INFORMATION);//图标
    wc.hInstance=hInstance;//应用程序的实际句柄。传入WinMain中的形参即可
    //wc.lpfnWndProc=WindowProc;//回调函数,窗口过程
    wc.lpszClassName=TEXT("WIN");//指定窗口类名称
    wc.lpszMenuName=NULL;//菜单名称
    wc.style=0;//显示风格,0代表默认风格
    //2. 注册窗口类
    RegisterClass(&wc);

    //3. 创建窗口
    /*
    lpClassName:类名
    lpWindowName:标题名
    dwStyle:风格
    x:显示坐标
    y:显示坐标CW_USEDEFAULT默认值
    nWidth:宽高
    nHeight
    hWndParent:父窗口
    hMenu:菜单NULL
    hInstance:实例句柄
    lpParam :附加值,鼠标附加值
    */
    hwnd = CreateWindow(wc.lpszClassName, TEXT("WINDOWS"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
    //4.显示和更新
    ShowWindow(hwnd,SW_SHOWNORMAL);
    UpdateWindow(hwnd);
    //5. 通过循环取消息
    /*
    HWND        hwnd;主窗口句柄
    UINT        message;具体的消息名称
    WPARAM      wParam;附加消息,键盘消息
    LPARAM      lParam;附加消息,鼠标消息
    DWORD       time;消息产生的时间
    POINT       pt;附加消息,鼠标消息 x y
    */
    
    while(1)
    {
        /*
        __out LPMSG lpMsg,消息
        __in_opt HWND hWnd,捕获窗口,填NULL代表捕获所有的窗口
        __in UINT wMsgFilterMin,最小和最大的过滤消息,一般填0
        __in UINT wMsgFilterMax 填0代表捕获所有消息
        */
        if(GetMessage(&msg,NULL,0,0)==FALSE)
        {
            break;
        }
        //翻译消息
        TranslateMessage(&msg);

        //不为false
        //分发消息
        DispatchMessage(&msg);

    }

    return 0;
}

注意:生成解决方案的时候出现“error C2275: “xxxxx”: 将此类型用作表达式非法”

           错误是由于:c的编译器要求将变量的声明放在一个函数块的头部,而c++没有这样的要求造成的;解决的办法就是把变量的声明全部放在变量的生存块的开始。

           解决方法:将所有变量定义在代码段的开头

 

 

MFC入门

MFC是什么?

微软基础类库(英语:Microsoft Foundation Classes,简称MFC)是一个微软公司提供的类库(class libraries),以C++类的形式封装了Windows API,并且包含一个应用程序框架,以减少应用程序开发人员的工作量。其中包含的类包含大量Windows句柄封装类和很多Windows的内建控件和组件的封装类。

MFC把Windows SDK API函数包装成了几百个类,MFC给Windows操作系统提供了面向对象的接口,支持可重用性、自包含性以及其他OPP原则。MFC通过编写类来封装窗口、对话框以及其他对象,引入某些关键的虚函数(覆盖这些虚函数可以改变派生类的功能)来完成,并且MFC设计者使类库带来的总开销降到了最低。

 

编写第一个MFC应用程序

1) 代码的编写

项目的创建和之前一样,只是此次的源文件后缀为.cpp,因为MFC是由C++编写的,编写MFC程序需要包含#include <afxwin.h>头文件

 

 

2) 程序执行流程

① 程序开始时,先实例化应用程序对象(有且只有一个)

② 执行程序的入口函数InitInstance()

③ 给框架类MyFrame对象动态分配空间(自动调用它的构造函数),在其构造函数内部,通过CWnd::Create创建窗口

④ 框架类对象显示窗口CWnd::ShowWindow

⑤ 框架类对象更新窗口CWnd::UpdateWindow

⑥ 保存框架类对象指针CWinThread::m_pMainWnd

 自定义类 继承与CWinApp应用程序类 MyApp app 应用程序对象,有且仅有一个

#include "mfc.h"

MyApp app;//全局应用程序对象,有且仅有一个
BOOL MyApp::InitInstance()
{
    //创建窗口
    MyFrame * frame=new MyFrame;
    //显示和更新
    frame->ShowWindow(SW_SHOWNORMAL);
    frame->UpdateWindow();
    m_pMainWnd=frame;//保存指向应用程序的主窗口的指针
    return TRUE;//返回正常初始化

}

MyFrame::MyFrame()
{
    Create(NULL,TEXT("mfc"));
}

 

#include <afxwin.h> //mfc头文件

class MyApp:public CWinApp///应用程序类
{
public:
    //程序入口
    virtual BOOL InitInstance();
};
class MyFrame:public CFrameWnd//窗口框架类
{
public:MyFrame();
};

 

消息映射

消息映射是一个将消息和成员函数相互关联的表

比如,框架窗口接收到一个鼠标左击消息,MFC将搜索该窗口的消息映射,如果存在一个处理WM_LBUTTONDOWN消息的处理程序,然后就调用OnLButtonDown

下面是是将消息映射添加到一个类中所做的全部工作:

1) 所操作类中,声明消息映射宏。

2) 通过放置标识消息的宏来执行消息映射,相应的类将在对BEGIN_MESSAGE_MAP和END_MESSAGE_MAP的调用之间处理消息。

3) 对应消息处理函数分别在类中声明,类外定义:

 

声明宏  写到h中

分界宏 写到.cpp中

找到消息宏,写到分界宏之间

把函数原型声明写到.h 中

函数的实现写到.cpp中

鼠标,键盘,绘图

 

#include "mfc.h"

MyApp app;//全局应用程序对象,有且仅有一个
BOOL MyApp::InitInstance()
{
    //创建窗口
    MyFrame * frame=new MyFrame;
    //显示和更新
    frame->ShowWindow(SW_SHOWNORMAL);
    frame->UpdateWindow();
    m_pMainWnd=frame;//保存指向应用程序的主窗口的指针
    return TRUE;//返回正常初始化

}
//分界宏
BEGIN_MESSAGE_MAP(MyFrame,CFrameWnd)
    ON_WM_LBUTTONDOWN( )//鼠标左键按下
    ON_WM_CHAR( )//键盘
END_MESSAGE_MAP()


MyFrame::MyFrame()
{
    Create(NULL,TEXT("mfc"));
}

void MyFrame::OnLButtonDown( UINT nFlags, CPoint point )
{
    /*TCHAR buf[1024];
    wsprintf(buf,TEXT("x=%d,y=%d"),point.x,point.y);
    MessageBox(buf);*/

    //mfc中的字符串  CString
    CString str;
    str.Format(TEXT("x=%d,,,,y=%d"),point.x,point.y);
    MessageBox(str);
}

void MyFrame::OnChar( UINT nChar, UINT nRepCnt, UINT nFlags )
{
    CString str;
    str.Format(TEXT("按下了%c 键"),nChar);
    MessageBox(str);
}
#include <afxwin.h> //mfc头文件

class MyApp:public CWinApp///应用程序类
{
public:
    //程序入口
    virtual BOOL InitInstance();
};
class MyFrame:public CFrameWnd//窗口框架类
{
public:MyFrame();
       //声明宏 提供消息映射机制
       DECLARE_MESSAGE_MAP()
       afx_msg void OnLButtonDown( UINT nFlags, CPoint point );
       afx_msg void OnChar( UINT nChar, UINT nRepCnt, UINT nFlags );

};

 

 Windows字符集

1. 多字节 字符串 转宽字节 L

2. 声明 宽字节字符串 wchar_t

3. 统计宽字节字符串 wcslen

4. TEXT做了自适应编码的转换

5. char * CString 之间转换

    char*->CString

    char * p3='ccc';

    CString str=Cstring(p3);

    CString->char *

    CString tmp;

     tmp=str;

     char *pp=tmp.GetBuffer();

用向导生成一个MFC应用程序

MFC框架中一些重要的函数

1) InitInstance函数

应用程序类的一个虚函数,MFC应用程序的入口。

 

2) PreCreateWindow函数

 

当框架调用CreateEx函数创建窗口时,会首先调用PreCreateWindow函数。

通过修改传递给PreCreateWindow的结构体类型参数CREATESTRUCT,应用程序可以更改用于创建窗口的属性。

在产生窗口之前让程序员有机会修改窗口的外观。

最后再调用CreateWindowEx函数完成窗口的创建。

 

3) OnCreate函数

 

OnCreate是一个消息响应函数,是响应WM_CREATE消息的一个函数,而WM_CREATE消息是由Create函数调用的。一个窗口创建(Create)之后,会向操作系统发送WM_CREATE消息,OnCreate()函数主要是用来响应此消息的。

onCreate与Create的区别:

1. Create()负责注册并产生窗口,像动态创建控件中的Create()一样,窗口创建之后会向操作系统发送WM_CREATE消息。

2. OnCreate()不产生窗口,只是在窗口显示前设置窗口的属性如风格、位置等。

3. OnCreate()是消息WM_CREATE的消息响应函数。 

 

4) OnDraw和OnPaint

 

OnPaint是WM_PAINT消息的消息处理函数,在OnPaint中调用OnDraw,一般来说,用户自己的绘图代码应放在OnDraw中。

1. OnPaint()是CWnd的类成员,负责响应WM_PAINT消息。

2. OnDraw()是CView的成员函数,没有响应消息的功能。

当视图变得无效时(包括大小的改变,移动,被遮盖等等),Windows发送WM_PAINT消息。该视图的OnPaint 处理函数通过创建CPaintDC类的DC对象来响应该消息并调用视图的OnDraw成员函数。OnPaint最后也要调用OnDraw,因此一般在OnDraw函数中进行绘制。

通常我们不必编写OnPaint处理函数。当在View类里添加了消息处理OnPaint()时,OnPaint()就会覆盖掉OnDraw()。

如果有了OnDraw,不要再有OnPaint了,同时存在的话,OnPaint会把OnDraw覆盖掉

 

 

转自:https://www.cnblogs.com/yangyuqing/p/10283641.html

posted @ 2020-12-16 10:50  二十一19  阅读(339)  评论(0编辑  收藏  举报