• 【MFC】第一个窗口程序(整理)(3)


    从控制台程序到窗口程序,还需要解决多个文件的问题。看到MFC创建的很多类型文件,初学者肯定 “忐忑不安”。

    整理程序

    从结构化编程的思想来看,独立的功能模块,应该封装成函数。同时为了方便管理,类似的功能模块可以集中在一起,不同的功能组应该分开管理。所以,对第一个窗口程序进行整理。

    项目按功能划分为三大块:主函数、初始化、窗口函数

    每块都按照一个头文件+一个源文件 的格式来设计,块之间功能的调用则只需要包含相应的头文件即可。合计 6 个文件:

    1、初始化函数分为两大功能:创建并注册窗口类, 根据注册的窗口类名创建主窗口

    头文件 Init.h:

    1. #ifndef INIT_H
    2. #define INIT_H
    3. #include "main.h"
    4. HWND InitInstance(HINSTANCE hInstance,int nCmdShow);
    5. BOOL InitApplication(HINSTANCE hInstance);
    6. #endif

    #ifndef INIT_H
    #define INIT_H

    ......

    #endif

    是通过预编译语句避免重复包含,如 A 包含 X 头文件,B 包含 X 和 A,这样就存在重复包含X的问题,但是可以利用文件名的唯一性(把 点换成 _ ),判断是否定义宏来避免。

    还有更简单的方式: #pragma once    可以完成以上功能。

    源文件: Init.cpp

    1. #include "init.h"
    2. #include "wndproc.h"
    3. char szAppName[]="AppName"; //指定窗口类名称
    4. char szTitle[]="Second API Application"; //窗口标题
    5. BOOL InitApplication(HINSTANCE hInstance) //自定义函数
    6. {
    7. WNDCLASS wc; //利用系统提供的类型定义变量存储窗口类数据
    8. wc.style=CS_VREDRAW|CS_HREDRAW; //窗口类风格
    9. wc.lpfnWndProc=MainWndProc; //指定窗口消息处理函数(Finit.cpp)
    10. wc.cbClsExtra=0; //额外分配在类数据结构尾端的字段数
    11. wc.cbWndExtra=0; //额外分配在应用程序运行副本尾端的字段数
    12. wc.hInstance=hInstance; //应用程序实例句柄(来自WinMain函数)
    13. wc.hIcon=LoadIcon(hInstance,NULL); //最小化时图标
    14. wc.hCursor=LoadCursor(NULL,IDC_ARROW); //鼠标光标
    15. wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //背景颜色
    16. wc.lpszMenuName=NULL; //窗口菜单
    17. wc.lpszClassName=szAppName; //给窗口类起个名称
    18. return(RegisterClass(&wc)); //窗口类注册
    19. }
    20. //产生应用程序的主窗口,并以nCmdShow指定方式显示
    21. HWND InitInstance(HINSTANCE hInstance,int nCmdShow) //自定义函数
    22. {
    23. HWND hwnd; //利用系统提供的类型定义窗口句柄
    24. hwnd = CreateWindow(//Windows系统接口函数(Windows API)
    25. szAppName, //窗口类名称(在wc.lpszClassName中指定)
    26. szTitle, //窗口标题
    27. WS_OVERLAPPEDWINDOW, //窗口风格,无标题栏
    28. 0, //窗口左上角x坐标
    29. 0, //窗口左上角y坐标
    30. GetSystemMetrics(SM_CXFULLSCREEN), //窗口宽度
    31. GetSystemMetrics(SM_CYFULLSCREEN)+60, //窗口高度
    32. NULL, //父窗口句柄
    33. NULL, //窗口菜单句柄
    34. hInstance, //程序实例句柄
    35. NULL //提供窗口使用的额外数据
    36. );
    37. if (!hwnd)
    38. return NULL; //未能正常产生窗口
    39. //Windows系统接口函数(Windows API)
    40. ShowWindow(hwnd,nCmdShow); //以nCmdShow指定方式显示窗口
    41. UpdateWindow(hwnd); //更新用户区
    42. return hwnd;
    43. }

    类名和窗口标题做成了全局变量(尽量避免),另外,函数的命名可能与功能不太匹配。

    2、窗口函数用于处理窗口消息,这是窗口应用程序关注的重点,MFC费尽心思就是想让程序员集中精力于处理消息响应,事与愿违,造成了MFC入门困难的窘境。

    头文件:wndproc.h

    1. #ifndef WNDPROC_H
    2. #define WNDPROC_H
    3. #include "main.h"
    4. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
    5. WPARAM wParam, LPARAM lParam);
    6. #endif

    源文件:wndproc.cpp

    1. #include "wndproc.h"
    2. LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
    3. WPARAM wParam, LPARAM lParam)
    4. {
    5. switch (message)
    6. {
    7. case WM_ERASEBKGND:
    8. {
    9. HDC hdc = ::GetDC(hWnd);
    10. RECT rect;
    11. ::GetClientRect(hWnd,&rect);
    12. ::FillRect(hdc,&rect,(HBRUSH)::GetStockObject(WHITE_BRUSH));
    13. break;
    14. }
    15. /*
    16. case WM_PAINT:
    17. {
    18. PAINTSTRUCT ps;
    19. HDC hdc = ::BeginPaint(hWnd,&ps);
    20. RECT rect;
    21. ::GetClientRect(hWnd,&rect);
    22. ::FillRect(hdc,&rect,(HBRUSH)::GetStockObject(GRAY_BRUSH));
    23. ::EndPaint(hWnd,&ps);
    24. break;
    25. }*/
    26. case WM_CLOSE:
    27. {
    28. ::DestroyWindow(hWnd);
    29. break;
    30. }
    31. case WM_DESTROY: //如果按下关闭按钮
    32. {
    33. PostQuitMessage(0); //发出关闭程序的消息
    34. break;
    35. }
    36. default: //其他消息发给windows默认窗口处理函数
    37. return (DefWindowProc(hWnd,message,wParam,lParam));
    38. }
    39. return 0;
    40. }

    3、主函数,MFC屏蔽了主函数(编译的时候加入),让初学者对程序的流程很难理解,心怀忐忑

    头文件:Main.h 

    1. #ifndef MAIN_H
    2. #define MAIN_H
    3. #include
    4. #endif

    在其他头文件中包含Main.h ,主要是需要 #include ,当然有更好的办法,就是把#include 写入 stdafx.h (预编译头文件,常用的头文件和宏都可以在这里包含或者定义)。

    源文件:Main.cpp

    1. #include "main.h"
    2. #include "init.h"
    3. int WINAPI WinMain(HINSTANCE hInstance, //应用程序当前实例句柄
    4. HINSTANCE hPrevInstance, //应用程序前一个实例句柄
    5. LPSTR lpCmdLine, //命令行字符窜指针
    6. int nCmdShow) //应用程序的显示方式
    7. {
    8. HWND hwnd; //窗口句柄
    9. MSG msg; //消息结构变量
    10. if (!InitApplication(hInstance)) //若注册窗口类失败,自定义函数(Finit.cpp)
    11. return false;
    12. //产生应用程序的主窗口,并以nCmdShow指定方式显示,自定义函数(Finit.cpp)
    13. hwnd=InitInstance(hInstance,nCmdShow);
    14. if (!hwnd)
    15. return false;
    16. while (::GetMessage(&msg,NULL,NULL,NULL))
    17. {
    18. if (msg.message==WM_QUIT) //如果接受到退出的消息WM_QUIT,整个程序将结束.
    19. break;
    20. TranslateMessage(&msg); //把键盘消息组合成相对的字符消息
    21. DispatchMessage(&msg);
    22. }
    23. return(msg.wParam);
    24. }

  • 相关阅读:
    Spark Overview
    ESP32-SPI接口bl0942驱动
    Leetcode 2926. Maximum Balanced Subsequence Sum
    环路与快速破环
    java--进制详解
    Prometheus性能调优-什么是高基数问题以及如何解决?
    如何在现货贵金属白银中超越自我
    @requestBody与@RequestParam
    如何实现基于 SaaS 的多租户多因素认证(MFA)?
    如何不编写 YAML 管理 Kubernetes 应用?
  • 原文地址:https://blog.csdn.net/yixiaobo2001/article/details/127801004