录十六

持之以恒

创建Windows窗口

本片博文属于Window编程的相关知识,对Windows开发很熟悉的读者可直接无视。

一、创建空项目

1、打开Visual Studio开发工具,版本可以随便选择,我个人使用的版本是Microsoft Visual studio 2010。

2、从菜单栏中依次选择【文件】­—【新建】—【项目】菜单项,打开新建项目对话框;在项目类型列表中选择Win32,模板类型选择Win32控制台应用程序,然后输入项目名称。如下图所示:

3、点击确定后,会弹出一个向导,继续单击【下一步】,弹出应用程序设置向导,应用程序类型选择Windows应用程序,附加选项选择空项目,如下图所示。

4、单击完成,这样一个空项目便创建成功了。

二、添加入口函数

上面我们创建好了空项目,接下来就需要我们自己添加代码了。按照以下几步就可轻松完成:

1、打开【解决方案资源管理器】,在“源文件”文件夹上右击,从菜单中找到【添加】—【新建项】,打开添加新项对话框,类别选择visual c++,模板选择c++文件,然后输入文件名称,如下图所示:

2、添加完成后,在解决方案的源文件目录下面会出现一个空的TestMain.cpp文件,首先在源文件中包含Windows.h头文件,这个是最基本的。

//包含Windows.h头文件.
#include <windows.h>

接下来在原文件中增加应用程序的入口函数WinMain,学过标准C++的朋友,应该都知道每个应用程序运行时都会先进入入口点函数main,而当从main函数跳出时,程序就结束了。在Windows编程里面,也是一样的,只是入口点函数不是main,而是WinMain,它的声明形式是固定死的,不能随便改的。如果忘记了,可以在MSDN中查找一下即可。

//入口函数
int CALLBACK WinMain(HINSTANCE hInstance, 
		    HINSTANCE hPrevInstance, 
		    LPSTR lpCmdLine, 
		    int nCmdShow) 
{ 
     return 0; 
}

3、编写完成后,我们编译一下工程,如果能编译通过,则说明项目的创建以及代码编写都没有问题。

三、创建窗口

用Windows API创建应用程序窗口,主要包括下面五个步骤:

  1. (1) 注册窗口

  2. (2) 创建窗口

  3. (3) 处理消息

  4. (4) 显示窗口

  5. (5) 启动消息循环

既然步骤是固定的,那么就可以按照步骤,一步步来创建窗口,首先在源文件中增加下面两个全局变量和两个空函数:

//应用程序实例句柄
HINSTANCE g_windows_instance= 0;
//windows窗口句柄
HWND      g_windows_hwnd   = 0;
LRESULT CALLBACK window_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
     LRESULT  ret=0;
     return ret;
}

bool init(unsigned width, unsigned height)
{
     return true;
}

首先在init函数中实现注册窗口和创建窗口,这个函数代码有点多,不过很简单,大家可以慢慢看,代码里增加了比较详细的注释。完整的函数如下:

// 初始化函数
bool init(unsigned width, unsigned height)
{

     WNDCLASS wc;

     // 设计窗口
     wc.lpszClassName = TEXT("AGGAppClass");      //注册窗口类名
     wc.lpfnWndProc = window_proc;                //窗口过程
     wc.style = CS_VREDRAW |CS_HREDRAW;           //窗口风格
     wc.hInstance = g_windows_instance;           //应用程序实例
     wc.hIcon = LoadIcon(0,IDI_APPLICATION);      //应用程序图标
     wc.hCursor = LoadCursor(0,IDC_ARROW);        //应用程序光标
     wc.hbrBackground = (HBRUSH)(COLOR_WINDOW);   //窗口背景
     wc.lpszMenuName = NULL;                      //窗口菜单名      
     wc.cbClsExtra = 0;                           //默认
     wc.cbWndExtra = 0;                           //默认

      //1. 注册窗口
     if(!RegisterClass(&wc))
     {
         return 0;
     }

     //2. 创建窗口
     HWND hwnd = CreateWindow( 
		TEXT("AGGAppClass"),   //类名,要和刚才注册的一致
		L"我的应用程序",        //窗口标题文字
		WS_OVERLAPPEDWINDOW,   //窗口外观样式
		38,                    //窗口相对于父级的X坐标
		20,                    //窗口相对于父级的Y坐标
		width,                 //窗口的宽度
		height,                //窗口的高度
		NULL,                  //没有父窗口,为NULL 
		NULL,                  //没有菜单,为NULL 
		g_windows_instance,    //当前应用程序的实例句柄
		NULL);                 //没有附加数据,为NULL 

     // 检查窗口是否创建成功
     if(!hwnd)               
     {
         return 0; 
     }
     
     return true;
}

接下来继续实现窗口消息处理的函数,由于目前的窗口什么事情也不需要干,所以暂时只处理窗口退出的消息,其他消息先不管,最终完成的函数代码如下:

// 3. 消息处理
LRESULT CALLBACK window_proc(HWND hWnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
     LRESULT  ret=0;
     switch(msg)
     {
        case WM_CREATE:
        {
            g_windows_hwnd=hWnd; // 保存窗口句柄
        }
        break;    
        case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd,&ps);//取得设备内容句柄 
            
            //添加Window绘图代码……
            
            EndPaint(hWnd,&ps);//释放句柄
        }
        break;
        case WM_DESTROY:
        {
            ::PostQuitMessage(0); // 窗口退出消息		
        }
        break;
        default:
            ret = ::DefWindowProc(hWnd,msg,wParam,lParam);
     }
     return ret;
}

【注意】:在window_pro中处理WM_PAINT时,必须调用BeginPaint和EndPaint函数处理绘图消息,否则系统会不断的投放WM_PAINT绘图消息,造成CPU占用率过高。

创建窗口的五个步骤,我们已经实现了三步,下来我们再增加一个run函数,完成最后两步。run函数的实现如下:

//运行函数
int run()
{
     MSG msg; 
     //4. 显示窗口
     ShowWindow(g_windows_hwnd,SW_SHOW|SW_NORMAL);
     //5. 消息循环
     while(GetMessage(&msg,NULL, 0,0)) 
     { 
          TranslateMessage(&msg); 
          DispatchMessage(&msg); 
     }
     return (int)msg.wParam;
}

最后修改一下WinMain函数,去调用我们封装的init和run两个函数,实现最终的窗口创建,修改之后的WinMain函数如下:

//入口函数
int CALLBACK WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance, 
                     LPSTR lpCmdLine, 
                     int nCmdShow) 
{ 
     g_windows_instance =hInstance;
     init(400, 400);
     run();
     return 0; 
}

四、运行结果

最后编译运行下,期待已久的窗口就出来,运行截图如下。

4.jpg

源码下载: CreateWindow

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

Copyright © 1999-2019, lu16.com, All Rights Reserved