初识MFC,一个简单的窗口程序


说明(期间写代码使用的VS2015,写博时用的VS2017,有些许差异,见谅)

1.字符问题
照着书上抄代码都发现了问题,书上使用的是VC++,本人使用的VS2015,存在着一些字符格式问题。
VS2015默认的是Unicode字符集,VC使用多字符字符集,当然你也可以去VS里面改设置,这是后话,暂且不表。
在其中,遇到了(wchar_t)类型的数据,都知道,char占一个字节,而wchar_t占两个字节,就是char的扩展类型,它自己也有一套函数集,比如求wchar_t数组长度的函数为wcslen,虽有变化,大致相同,熟悉就好了。

 

2.Win32 Application 和 Win32 Console Application 之间的区别
(不记得是哪里抄的一段话了。。。。)
1、程序不同
Win32 Application 是标准windows程序,完全拥有windows的特性,可以通过鼠标点击窗口来完成控制。(入口函数–WinMain)
Win32 Console Application是控制台应用程序,类似于MS-DOS窗口,只能运行命令行程序,不具备消息响应机制。(入口函数–main)
2、入口函数不同
Win32 Application 入口函数是WinMain(),它具有消息响应机制,可以运行图形化的C++程序。
Win32 Console Application入口函数是main(),可以访问部分windows API函数,如果你编写传统的C程序,必须建立Win32 Console程序。
3、Win32 Application它通过GUI(Graphics User Interface图形用户接口)可以把窗口界面做得比较个性化,比如圆形的、不规则形状的等等,另外,我们还可以通过鼠标点击来完成控制。所以说它是基于WINDOWS平台的32位开发环境开发应用程序(即,SDK程序)。入口函数为WinMain()。Win32 Console Application(win32控制台应用程序)往往是像MS-DOS窗口(XP中叫命令提示符)的样子出现,我们得用键盘输入各种命令来使用它,它与纯dos程序区别是:它是32位的;或者叫CUI(Character User Interface字符用户接口)。console程序以main()为入口,可以访问部分windows API函数,比如创建窗口、对话框等等。

 

3.第一个Windows程序–WinMain
VS(文件 -> 新建 -> 项目 -> windows桌面 -> Windows桌面应用程序 )反正就是创建一个win32项目的空项目(没有初始代码的那种,VS版本不同显示的新建项也不同,不过总而言之,建一个空白Windows桌面应用程序(Win32 Application)就可以了)建不了空白的也无妨,把文件删一下就可以。
首先新建一个cpp文件,用于编写代码(因为建的是一个空项目),如下图所示:

初识MFC,一个简单的窗口程序

 

 

然后开始编写代码: 可以划分为以下七步—>>>
1.编写Win Main函数 —————- 类似于编写main函数,都是入口函数
2.设计窗口类,WNDCLASS ———— 有过封装,直接使用,设置参数
3.注册窗口类 ———– 需要先注册
4.创建窗口 ————– 创建
5.显示并更新窗口 ——– 显示
6.编写消息循环 ———– 循环查询消息队列,处理消息,针对不同的消息做出不同响应(由此实现一个应用程序)
7.编写窗口过程函数 —— 怎么响应消息(对消息做出对应的处理)

其中使用的各个函数在代码中有相应注释:

_T(),主要就是解决字符编码问题,真麻烦,感觉 (可以去链接看一下)

MSG可以直接理解为一个消息结构体,存储着不同的消息。

最后可以发现,程序关闭时的消息传递是:WM_CLOSE -> WM_DESTROY -> WM_QUIT,后面还会遇到,暂且不表。

  1 #include <windows.h>
  2 #include <stdio.h>
  3 
  4 #include <tchar.h>
  5 
  6 /*
  7     窗口过程函数的声明 WinSunProc
  8 */
  9 LRESULT CALLBACK WinSunProc(
 10     HWND hwnd,        // 窗口句柄
 11     UINT uMsg,        // 消息标识符
 12     WPARAM wParam,    // unsigned int 
 13     LPARAM lParam    // long  两个附加信息
 14 );
 15 
 16 
 17 /*
 18     WinMain(),入口函数
 19     HINSTANCE hInstance;程序当前运行的实例的句柄
 20     HINSTANCE hPrevInstance;当前实例的前一个实例的句柄,win32环境hPrevInstance = null,参数无用
 21     LPSTR lpCmdLine;传递应用程序的命令行参数,以空终止的字符串
 22     int nCmdShow;窗口显示效果,最大/最小/隐藏
 23 */
 24 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
 25 {
 26     /*
 27         设计窗口类
 28     */
 29     WNDCLASS wndcls;        // 定义一个窗口类
 30     // 设置该窗口的各个参数
 31     wndcls.cbClsExtra = 0;
 32     wndcls.cbWndExtra = 0;
 33     wndcls.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
 34     wndcls.hCursor = LoadCursor(NULL, IDC_CROSS);
 35     wndcls.hIcon = LoadIcon(NULL, IDI_ERROR);
 36     wndcls.hInstance = hInstance;
 37     wndcls.lpfnWndProc = WinSunProc;                // 窗口过程函数
 38     wndcls.lpszClassName = _T("sunxin2006");        // 窗口类名
 39     wndcls.lpszMenuName = NULL;                        // 菜单
 40     wndcls.style = CS_HREDRAW | CS_VREDRAW;
 41 
 42     /*
 43         注册窗口类
 44     */
 45     RegisterClass(&wndcls);                            // 注册窗口类
 46 
 47     /*
 48         创建窗口类
 49     */
 50     HWND hwnd;        // 窗口句柄
 51     // 创建窗口
 52     hwnd = CreateWindow(_T("sunxin2006"), _T("Windows程序"), WS_OVERLAPPEDWINDOW, 0, 0, 600, 400, NULL, NULL, hInstance, NULL);
 53 
 54     /*
 55         显示与更新窗口
 56     */
 57     ShowWindow(hwnd, SW_SHOWNORMAL);        // 激活并显示,窗口正常大小,(第一次显示
 58     // 目前,整个客户区无效, UpdateWindow 会检查窗口的 Update Region无效区域,当其不为空时才发送 WM_PAINT 消息
 59     // 所谓无效区域就是需要应用程序重新绘制的区域,反之则为有效区域 => 有无效区域时,发送WM_PAINT消息
 60     UpdateWindow(hwnd);                        // 会发送一个WM_PAINT信息
 61 
 62     MSG msg;            // 消息结构体
 63     // 消息循环代码
 64     while (GetMessage(&msg, NULL, 0, 0))        // GetMessage函数接收WM_QUIT返回0,此外非0,出错-1
 65     {
 66         // GetMessage函数 要检索其消息的窗口的句柄。该窗口必须属于当前线程。
 67         // 如果 hWnd 为 NULL,则 GetMessage 将检索属于当前线程的任何窗口的消息,以及当前线程的消息队列中hwnd 值为 NULL 的任何消息。
 68         // 因此,如果 hWnd 为 NULL,则同时处理窗口消息和线程消息。
 69         // 如果 hWnd 为 - 1,则 GetMessage 仅检索当前线程的消息队列中hwnd值为 NULL 的消息
 70         TranslateMessage(&msg);                    // 把快捷键消息转换为字符消息,并将转换后的新消息投递到调用线程的消息队列中
 71         DispatchMessage(&msg);
 72         // DispatchMessage函数分发一个消息给窗口程序,通常消息从GetMessage函数获得或者TranslateMessage函数传递的
 73         // 消息被分发到回调函数(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息。
 74 
 75         // 函数DispatchMessage()负责将消息派送到相应的窗口函数。它根据msg结构中的hWnd窗口句柄成员找到相应的窗口类,
 76         // 然后根据注册窗口时wndcls类结构找到相应的窗口函数WinSunProc。由消息传递函数将消息传递给窗口函数WinSunProc进行消息处理。
 77     }
 78     return msg.wParam;
 79 }
 80 
 81 LRESULT CALLBACK WinSunProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
 82 {
 83     switch (uMsg)
 84     {
 85     case WM_CHAR:        //字符信息    char * -> WCHAR *
 86         // char szChar[20];
 87         // sprintf(szChar, "char code is %d", wParam);
 88         // MessageBox(hwnd, _T(szChar), _T("char"), 0);
 89         wchar_t szChar[20];
 90         swprintf(szChar, 100, L"char code is %d", wParam);
 91         MessageBox(hwnd, szChar, _T("char"), 0);
 92         break;
 93     case WM_LBUTTONDOWN:        // 鼠标左键信息
 94         MessageBox(hwnd, _T("mouse clicked"), _T("message"), 0);
 95         HDC hdc;                // 为 DVTARGETDEVICE 结构中指定的设备创建设备上下文, TextOut等函数所需参数
 96         hdc = GetDC(hwnd);        //不能在响应MWM_PAINT时调用    
 97         TextOut(hdc, 0, 50, _T("中文有什么问题吗?"), wcslen(_T("中文有什么问题吗?")));            // 位置坐标(0,50)
 98         // 中文乱码问题,wchar 与 char 所占空间不同,故而计算空间需要使用wcslen函数,
 99         ReleaseDC(hwnd,hdc);    // GteDC 配套函数,释放资源
100         break;
101     case WM_PAINT:                // 系统会在多个不同的时机发送 WM_PAINT 消息:当第一次创建窗口,改变窗口大小,把窗口移出,最大化,最小化时
102         HDC hDC;
103         PAINTSTRUCT ps;            // 绘图信息结构
104         hDC = BeginPaint(hwnd, &ps);        // BeginPaint只能在响应MWM_PAINT时调用    
105         // BeginPaint 的一个作用就是把该 Update Region(即无效区域) 置为空, => 全部为有效区域
106         // 这样如果不调用 BeginPaint,窗口的Update Region 就一直不为空,系统就会一直发送 WM_PAINT 消息。
107         TextOut(hDC, 100, 0, _T("http://www.qutuku.com"), strlen("http://www.qutuku.com"));
108         EndPaint(hwnd, &ps);        // 释放 hDC
109         break;
110     case WM_CLOSE:
111         if (IDYES == MessageBox(hwnd, _T("是否真的结束?"), _T("message"), MB_YESNO))
112         {
113             DestroyWindow(hwnd);
114         }
115         break;
116     case WM_DESTROY:                // DestroyWindow销毁后会发送一个WM_DESTROY消息,
117         PostQuitMessage(0);            // PostQuitMessage向应用程序的消息队列中投递一条 WM_QUIT 消息,并返回
118         break;                        // GetMessage(&msg, NULL, 0, 0)收到 WM_QUIT 消息,循环结束
119     default:
120         return DefWindowProc(hwnd, uMsg, wParam, lParam);
121         // DefWindowProc这个函数是默认的窗口处理函数,我们可以把不关心的消息都丢给它来处理
122     }
123     return 0;
124 }

主要还是熟悉整个运行流程,搞清楚有哪几步,每一步都是做一些什么样的工作,即可。

2022-07-31(07-13的工作,拖延症晚期。。)

原创文章,作者:bd101bd101,如若转载,请注明出处:https://blog.ytso.com/278155.html

(0)
上一篇 2022年8月1日
下一篇 2022年8月1日

相关推荐

发表回复

登录后才能评论