2025年4月3日 星期四 乙巳(蛇)年 正月初四 设为首页 加入收藏
rss
您当前的位置:首页 > 计算机 > 编程开发 > VC/VC++

MFC 基础入门

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

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