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

这篇博客介绍了如何将Windows控制台程序转换为窗口程序,通过将项目划分为主函数、初始化和窗口函数三个部分,并分别用头文件和源文件进行组织。文章详细讲解了每个部分的功能,包括窗口类的注册、主窗口的创建、窗口消息处理等,并展示了如何避免头文件重复包含。此外,还讨论了MFC在窗口程序设计上的挑战和初学者可能遇到的困惑。

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

整理程序

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

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

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

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

头文件 Init.h:

#ifndef INIT_H
#define INIT_H
#include "main.h"

HWND InitInstance(HINSTANCE hInstance,int nCmdShow);
BOOL InitApplication(HINSTANCE hInstance);

#endif

#ifndef INIT_H
#define INIT_H

......

#endif

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

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

源文件: Init.cpp

#include "init.h"
#include "wndproc.h"

char szAppName[]="AppName"; //指定窗口类名称
char szTitle[]="Second API Application";   //窗口标题

BOOL InitApplication(HINSTANCE hInstance) //自定义函数 
{
   WNDCLASS wc;           //利用系统提供的类型定义变量存储窗口类数据

   wc.style=CS_VREDRAW|CS_HREDRAW; //窗口类风格
   wc.lpfnWndProc=MainWndProc;  //指定窗口消息处理函数(Finit.cpp)
   wc.cbClsExtra=0;             //额外分配在类数据结构尾端的字段数
   wc.cbWndExtra=0;             //额外分配在应用程序运行副本尾端的字段数

   wc.hInstance=hInstance;      //应用程序实例句柄(来自WinMain函数)
   wc.hIcon=LoadIcon(hInstance,NULL);  //最小化时图标
   wc.hCursor=LoadCursor(NULL,IDC_ARROW);              //鼠标光标
   wc.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); //背景颜色
   wc.lpszMenuName=NULL;        //窗口菜单
   wc.lpszClassName=szAppName;  //给窗口类起个名称
   return(RegisterClass(&wc));  //窗口类注册
}


//产生应用程序的主窗口,并以nCmdShow指定方式显示
HWND InitInstance(HINSTANCE hInstance,int nCmdShow) //自定义函数 
{
   HWND hwnd;  //利用系统提供的类型定义窗口句柄

   hwnd = CreateWindow(//Windows系统接口函数(Windows API)
         szAppName,              //窗口类名称(在wc.lpszClassName中指定)
         szTitle,                //窗口标题
         WS_OVERLAPPEDWINDOW,               //窗口风格,无标题栏
         0,                      //窗口左上角x坐标
         0,                      //窗口左上角y坐标
         GetSystemMetrics(SM_CXFULLSCREEN),          //窗口宽度
         GetSystemMetrics(SM_CYFULLSCREEN)+60,       //窗口高度
         NULL,                   //父窗口句柄
         NULL,                   //窗口菜单句柄
         hInstance,              //程序实例句柄
         NULL                    //提供窗口使用的额外数据
       );

    if (!hwnd)
       return NULL;             //未能正常产生窗口

	//Windows系统接口函数(Windows API)
    ShowWindow(hwnd,nCmdShow);   //以nCmdShow指定方式显示窗口
    UpdateWindow(hwnd);          //更新用户区
    return hwnd;
}

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

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

头文件:wndproc.h

#ifndef WNDPROC_H
#define WNDPROC_H
#include "main.h"

LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
                            WPARAM wParam, LPARAM lParam);



#endif

源文件:wndproc.cpp

#include "wndproc.h"

LRESULT CALLBACK MainWndProc(HWND hWnd,UINT message,
                            WPARAM wParam, LPARAM lParam)
{
   switch (message)
   {       
   case WM_ERASEBKGND:
	   {
		  
		   HDC hdc = ::GetDC(hWnd);
		   RECT rect;
		   ::GetClientRect(hWnd,&rect);		
		   ::FillRect(hdc,&rect,(HBRUSH)::GetStockObject(WHITE_BRUSH));
         
		   break;	
		   }
	   /*
	   case WM_PAINT:
		   {
		   PAINTSTRUCT ps;
		   HDC hdc = ::BeginPaint(hWnd,&ps);
		   RECT rect;
		   ::GetClientRect(hWnd,&rect);		
		   ::FillRect(hdc,&rect,(HBRUSH)::GetStockObject(GRAY_BRUSH));
           ::EndPaint(hWnd,&ps);
		   break;	
		   }*/

   case WM_CLOSE:
	   {
		   ::DestroyWindow(hWnd); 
		   break;
	   }

   case WM_DESTROY:            //如果按下关闭按钮
        {
           PostQuitMessage(0); //发出关闭程序的消息
           break;
        }
   default:  //其他消息发给windows默认窗口处理函数
            return (DefWindowProc(hWnd,message,wParam,lParam));
   }
   return 0;
}

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

头文件:Main.h 

#ifndef MAIN_H
#define MAIN_H
#include <windows.h>

#endif

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

源文件:Main.cpp

#include "main.h"
#include "init.h"



int WINAPI WinMain(HINSTANCE hInstance,    //应用程序当前实例句柄
               HINSTANCE hPrevInstance,    //应用程序前一个实例句柄
               LPSTR lpCmdLine,            //命令行字符窜指针
               int nCmdShow)               //应用程序的显示方式
{   
   
   HWND hwnd;       //窗口句柄 
   MSG msg;          //消息结构变量  
   
   if (!InitApplication(hInstance))  //若注册窗口类失败,自定义函数(Finit.cpp)
      return false;

   //产生应用程序的主窗口,并以nCmdShow指定方式显示,自定义函数(Finit.cpp)
   hwnd=InitInstance(hInstance,nCmdShow);  
   if (!hwnd)
      return false;                        

   while (::GetMessage(&msg,NULL,NULL,NULL))
   {  
     
         if (msg.message==WM_QUIT)  //如果接受到退出的消息WM_QUIT,整个程序将结束.
            break;
         TranslateMessage(&msg); //把键盘消息组合成相对的字符消息
         DispatchMessage(&msg); 		 		

   }

   return(msg.wParam);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

易老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值