您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

MFC 基础入门

时间:08-19来源:作者:点击数:

windows底层 API 是由C语言写的,而MFC则是在此基础上通过C++进行了封装。

要想利用MFC进行编程,那么就得从main方法开始

MFC的main函数C的写法是

温馨小提示:函数变量名如果带有p的一般都是指针,入参的时候的传地址

#include <Windows.h>

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nShowCmd) {
	// 主程序内容。。。
}

下面是c++的写法

#include <Windows.h>

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPTSTR lpCmdLine, int nShowCmd) {
	// 主程序内容。。。
}

需要注意的是MFC的函数得加上 宏定义WINAPI表示参数的传递顺序,参数从右到左依次入栈,函数return前清空函数栈

  1. hInstance 当前音乐实例句柄
  2. hPrevInstance 上一个音乐程序句柄,在win32环境下一般为NULL
  3. lpCmdLine 类型LPTSTR 等同于 char* args[]
  4. nShowCmd 显示的命令 最大化、最小化、正常

写一个窗口程序主要分为

  1. 设计窗口
  2. 注册窗口
  3. 创建窗口
  4. 显示和更新
  5. 循环获取消息
  6. 处理消息

一、设计一个窗口

实际上windows已经把窗口封装成了一个结构体WNDCLASS,我们只需要对这个结构体内容进行补充,一个窗口类的信息就设置好了。

通过宏定义调整过去会发现结构体有下面这些内容

重复的内容不做额外解释

typedef struct tagWNDCLASSA {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCSTR      lpszMenuName;
    LPCSTR      lpszClassName;
} WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
typedef struct tagWNDCLASSW {
    UINT        style;		// 显示的风格(最大化、最小化、0 是默认值)
    WNDPROC     lpfnWndProc;// ==>窗口过程的回调函数(消息回调)
    int         cbClsExtra; // 类的额外的内存
    int         cbWndExtra; // 窗口额外的内存
    HINSTANCE   hInstance;	// 应用程序实例句柄
    HICON       hIcon;		// 窗口上方的图标
    HCURSOR     hCursor;	// 光标,wc.hCursor = LoadCursor(NULL,IDC_HAND);第一个参数为NULL表示使用系统光标,第二个参数表示鼠标的形状(指针,小手等)
    HBRUSH      hbrBackground;	// 背景,一般使用白色刷(HBRUSH) GetStockObject(WHITE_BRUSH);
    LPCWSTR     lpszMenuName;	// 指定窗口类名称
    LPCWSTR     lpszClassName;	// 指定才当名称
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
#ifdef UNICODE
typedef WNDCLASSW WNDCLASS;
typedef PWNDCLASSW PWNDCLASS;
typedef NPWNDCLASSW NPWNDCLASS;
typedef LPWNDCLASSW LPWNDCLASS;
#else
typedef WNDCLASSA WNDCLASS;
typedef PWNDCLASSA PWNDCLASS;
typedef NPWNDCLASSA NPWNDCLASS;
typedef LPWNDCLASSA LPWNDCLASS;
#endif // UNICODE

二、注册窗口

温馨提示:在调用API的时候会发现有些方法带W 或 A,是由于编码导致API 不同所致,W是Unicode编码的、A是Ascii码编码的,实际上在使用的过程中没有太大区别

WNDCLASS wc;
wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);// 设置背景
// 注册窗口类
RegisterClass(&wc);

三、创建窗口

创建窗口的函数定义如下,这几个方法名称很相似,实际上使用起来基本上一直

W 与 A 的区别就子啊与编码的不同而已

#define CreateWindowA(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExA(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#define CreateWindowW(lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)\
CreateWindowExW(0L, lpClassName, lpWindowName, dwStyle, x, y,\
nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam)
#ifdef UNICODE
#define CreateWindow  CreateWindowW
#else
#define CreateWindow  CreateWindowA
#endif // !UNICODE

通过点击CreateWindow跳转过去会找到完整的定义

HWND CreateWindowW(
  [in, optional]  lpClassName, // 窗口类名字(带p表示指针),字符串char *
  [in, optional]  lpWindowName,// 窗口的名称(带p表示指针),字符串char *
  [in]            dwStyle,		// WS_OVERLAPPEDWINDOW 风格
  [in]            x,			// 显示窗口的坐标 CW_USEDEFAULT
  [in]            y,			// (x,y)是窗口左上角那个点
  [in]            nWidth,		// 窗口宽
  [in]            nHeight,		// 窗口高
  [in, optional]  hWndParent,	// 父窗口句柄,NULL
  [in, optional]  hMenu,		// 窗口菜单句柄,NULL
  [in, optional]  hInstance,	// 实例句柄hInstance(winMain传进来的那个)
  [in, optional]  lpParam		// 鼠标附加值,左右键
);

四、显示和更新窗口

 //3、显示与更新窗口
 ShowWindow(hwnd, SW_SHOWNORMAL);
 UpdateWindow(hwnd);

五、循环获取消息

首先需要明白消息的结构内容,消息定义如下

消息结构体

#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)

/*
 * Message structure
 */
typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) */

获取消息的函数

WINUSERAPI
BOOL
WINAPI
GetMessageA(
    _Out_ LPMSG lpMsg,
    _In_opt_ HWND hWnd,
    _In_ UINT wMsgFilterMin,
    _In_ UINT wMsgFilterMax);
WINUSERAPI
BOOL
WINAPI
GetMessageW(
    _Out_ LPMSG lpMsg,		// 返回的消息
    _In_opt_ HWND hWnd,		// 捕获哪一个窗口的消息,如果为NULL则是捕获所有窗口消息,并且 min 和 max 为0
    _In_ UINT wMsgFilterMin,// 想要捕获所有消息则 min 和 max 都设置为0
    _In_ UINT wMsgFilterMax);
#ifdef UNICODE
#define GetMessage  GetMessageW
#else
#define GetMessage  GetMessageA
#endif // !UNICODE

完整的通过MFC创建一个窗口并且弹出一条消息

点击关闭窗口会调用DestroyWindow 进而触发WM_DESTROY消息,通过PostQuitMessage(0)才真正的关闭了窗口

#include <afx.h>
#include <Windows.h>
// 消息处理函数
LRESULT CALLBACK Wndproc(
        HWND hwnd, // 消息所属的窗口句柄
        UINT uMsg, // 具体消息名称 WM_XXXX 消息名
        WPARAM wparam,// 键盘附加消息
        LPARAM lparam // 鼠标附加消息
) {

    switch (uMsg) {
    	//点击关闭窗口的按钮,会发送一条WM_DESTROY消息
        case WM_CLOSE:
            DestroyWindow(hwnd);
            break;
        //处理销毁消息
        case WM_DESTROY:
            PostQuitMessage(0);//放弃后面所有消息(有结束窗口的含义)
            break;
        //鼠标左键弹起
        case WM_LBUTTONUP:
            int x = LOWORD(lparam);//鼠标的x轴
            int y = HIWORD(lparam);//鼠标的y轴位置
            CString  str;
            // 将坐标信息,通过字符串格式化
            str.Format(TEXT("弹出的消息:鼠标坐标x=%d,y=%d"),x,y);
            MessageBox(hwnd, str,TEXT("弹出框的标题"), MB_OK);// 一个消息弹窗
            break;
       

    }
    // 默认的消息处理
    return DefWindowProc(hwnd,uMsg,wparam,lparam);
}

extern "C" int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/,
                                LPTSTR /*lpCmdLine*/, int nShowCmd) {
    //1、定义窗口
    WNDCLASS wc;
    wc.lpszClassName = TEXT("WINDEMO");
    wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
    wc.hCursor = LoadCursor(NULL, IDC_HAND);
    wc.hIcon = LoadIcon(NULL, IDI_ERROR);
    wc.hInstance = hInstance;
    wc.style = 0;
    wc.lpszMenuName = NULL;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.lpfnWndProc = Wndproc;
    //2、注册窗口
    RegisterClass(&wc);
    // 创建窗口,宽高都为300,窗口标题为demo
    HWND hwnd = CreateWindowW(wc.lpszClassName, TEXT("demo"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
                              300, 300, NULL, NULL, hInstance, NULL);
    //3、显示与更新窗口
    ShowWindow(hwnd, SW_SHOWNORMAL);
    UpdateWindow(hwnd);
    //4、循环获取消息
    MSG msg;
    while (true) {
        if (GetMessage(&msg, NULL, 0, 0) == FALSE) {
            break;
        }
        // 翻译消息
        TranslateMessage(&msg);
        // 分发消息
        DispatchMessage(&msg);
    }

    return 0;
}
在这里插入图片描述
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门