综合

img ZQGet

如何创建原生的窗口程序

发表于2004/10/9 12:05:00  975人阅读

分类: Win32 编程

如何创建原生的窗口程序

 

如何创建原生的窗口程序现在用的已经不多了,因为现在的RAD工具普遍都是,用不着费尽心思去考虑那些窗口创建的细节,的确,一般不会有人会首先想到会用比较原始的方法来构建一般的窗口,可当你知道了那些原始的方法对你却是大大有好处的,我就深有体会,比如:用RAD开发工具创建的窗口往往是非常标准的,你如果想要创建一些特殊的窗口,那么就得更改你已创建的窗口,这时仍然要求你对如何创建原生窗口有所了解,何况当你知道了如何创建原生的窗口程序后,你会感觉到窗口原来还可以这样构建,同时你也会学到如何通过控制窗口的样式来更改窗口的风格等等。好了,下面我就来介绍一下如何创建原生的窗口程序,我使用的工具是Borland C++ Builder,也许和你们一样,也属于快速开发工具.

 

1、启动C++Builder(不在乎你的版本)新建一控制台程序,

2、在弹出的对话框中请确信只有C++ Radio Button被选中,如图:


3、单击OK按钮你将看到如下代码

#include <vcl.h>

#include <windows.h>

#pragma hdrstop

 

//---------------------------------------------------------------------------

 

#pragma argsused

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

    return 0;

}

 

其中WinMain函数是窗口程序的入口函数,就想CC++中的main函数一样,唯一不同的是CC++main函数的参数是可选的,而WinMain函数的参数是固定的,这也是你的程序和操作系统交换信息的地方。这几个参数表示如下:

 

第一个参数hInstance 表示你写的应用程序的句柄即标志

第二个参数hPrevInstance表示的是你程序的前一个实例句柄,条件是要有你程序的前一个实例在运行,如果没有的话,你可以忽略该参数。

第三个参数lpCmdLine是一个字符串,它主要的用途是相应命令行的命令,如你可能会用命令行的方式来编译程序

第四个参数nCmdShow控制你程序创建的窗口的显示

 

以上只是介绍了WinMain函数的参数而已,这才是创建原生窗口程序的开始,下面还有一些几乎固定的步骤来完成创建原生窗口程序的创建,步骤如下:

 

1、注册你要创建窗口的窗口类

2、根据注册的窗口类来创建并显示显示窗口

3、处理消息循环

 

注册你要创建窗口的窗口类

 

  Win32提供了WNDCLASS WNDCLASSEX类(其实都是结构体)可供我们使用,你只要用其中的一个就可以了,它们的定义如下:

 

typedef struct _WNDCLASS { 
    UINT       style; 
    WNDPROC    lpfnWndProc; 
    int        cbClsExtra; 
    int        cbWndExtra; 
    HINSTANCE  hInstance; 
    HICON      hIcon; 
    HCURSOR    hCursor; 
    HBRUSH     hbrBackground; 
    LPCTSTR    lpszMenuName; 
    LPCTSTR    lpszClassName; 
} WNDCLASS, *PW
typedef struct _WNDCLASSEX { 
    UINT       cbSize; 
    UINT       style; 
    WNDPROC    lpfnWndProc; 
    int        cbClsExtra; 
    int        cbWndExtra; 
    HINSTANCE  hInstance; 
    HICON      hIcon; 
    HCURSOR    hCursor; 
    HBRUSH     hbrBackground; 
    LPCTSTR    lpszMenuName; 
    LPCTSTR    lpszClassName; 
    HICON      hIconSm; 
} WNDCLASSEX, *PWNDCLASSEX;

 

在注册窗口类之前应该先初始化窗口类的实例,这时我们的任务就是如何来完成WNDCLASSEX 实例的初始化,如果完成了这一步,后面的事情就变得简单了。好了,下面我们就根据WNDCLASSEX的结构来一一构建窗口类

代码如下:

 

       WNDCLASSEX WndClsEx;

 

       WndClsEx.cbSize        = sizeof(WNDCLASSEX);

       WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;

       WndClsEx.lpfnWndProc   = WndProcedure;

       WndClsEx.cbClsExtra    = 0;

       WndClsEx.cbWndExtra    = 0;

       WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);

       WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);

       WndClsEx.hbrBackground = GetStockObject(WHITE_BRUSH);

       WndClsEx.lpszMenuName  = NULL;

       WndClsEx.lpszClassName = ClsName;//窗口类名的常量

       WndClsEx.hInstance     = hInstance;

       WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

 

这段代码中大部分的参数你可以参照MSDN来设置,我要说明一下的是以下几个方面

 

WndProcedure 为窗口的回调函数,主要用来处理窗口消息:

 

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

{

    switch(Msg)

    {

    case WM_DESTROY:

        PostQuitMessage(WM_QUIT);

        break;

default:         

//将不处理的消息交由系统来处理

        return DefWindowProc(hWnd, Msg, wParam, lParam);

 

    }

    return 0;

}

 

除了WndProcedure回调函数以外,还调用了LoadIcon(),LoadCursor(),GetStockObject()API函数来完成窗口图标,小图标,鼠标,背景颜色的设置,关于函数你可以参考MSDN来调用,同时还自定义了一些常数如:ClsName

完成了以上步骤后现在的程序代码如下:

 

#include <vcl.h>

#include <windows.h>

#pragma hdrstop

    //定义两个产量用来表示窗口类名和窗口名称

const char *ClsName = "窗口类名";

const char *WndName = "窗口名称";

    //窗口的回调函数,用来处理窗口消息

LRESULT CALLBACK WndProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)

{

    switch(Msg)

    {

    case WM_DESTROY:

        PostQuitMessage(WM_QUIT);

        break;

    default:

        return DefWindowProc(hWnd, Msg, wParam, lParam);

    }

    return 0;

}

//---------------------------------------------------------------------------

 

#pragma argsused

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)

{

       WNDCLASSEX WndClsEx;

 

       WndClsEx.cbSize        = sizeof(WNDCLASSEX);

       WndClsEx.style         = CS_HREDRAW | CS_VREDRAW;

       WndClsEx.lpfnWndProc   = WndProcedure;

       WndClsEx.cbClsExtra    = 0;

       WndClsEx.cbWndExtra    = 0;

       WndClsEx.hIcon         = LoadIcon(NULL, IDI_APPLICATION);

       WndClsEx.hCursor       = LoadCursor(NULL, IDC_ARROW);

       WndClsEx.hbrBackground = GetStockObject(WHITE_BRUSH);

       WndClsEx.lpszMenuName  = NULL;

       WndClsEx.lpszClassName = "窗口窗名称";

       WndClsEx.hInstance     = hInstance;

       WndClsEx.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

 

       return 0;

 

}

注册程序窗口

这测程序窗口很简单,只是简单的调用RegisterClassEx(&WndClsEx)函数即可完成,RegisterClassEx函数的参数即为上面定义的窗口类,代码如下:
WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
        WNDCLASSEX WndClsEx;
        。。。。。。
        RegisterClassEx(&WndClsEx);
        return 0;
}

创建并显示窗口

 创建窗口也很简单,只是调用CreateWindow函数就可搞定,只是如果你还想在你的程序中使用你创建的窗口的话,你应该设置一个用来保存窗口的窗口句柄,代码如下:

 

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                                  LPSTR lpCmdLine, int nCmdShow)
{
        HWND    hWnd;
        WNDCLASSEX     WndClsEx;
        . . .
         RegisterClassEx(&WndClsEx);
 
        hWnd = CreateWindow(
              ClsName,
                         WndName,
                         WS_OVERLAPPEDWINDOW,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         CW_USEDEFAULT,
                         NULL,
                         NULL,
                         hInstance,
                         NULL);
        if( !hWnd )return 0; //如果窗口创建失败的话则退出程序
 
            //显示所创建的窗口
        ShowWindow(hWnd, SW_SHOWNORMAL);
        UpdateWindow(hWnd);

}

 

这样就完成了窗口的创建和显示了,可是当我们去运行程序时却发现我们创建的窗口一闪而过,程序马上就结束了,这不是我们需要的,如何解决这个问题呢,其实,上面我也已经说了,还有一个步骤没有完成嘛,那就时消息循环,只有建立了消息循环以后,程序窗口才不会消失,原因很简单,因为程序一直处于循环之中,它就始终没有结束,所以我们创建的窗口也就不会显示了。

 

处理消息循环:

       消息循环的处理主要是用到了GetMessage,TranslateMessage DispatchMessage这三个API函数,GetMessage的作用是取得程序的消息队列中取得窗口消息,TranslateMessage函数的作用是处理GetMessage函数取得的消息的格式以致于能够被应用程序识别,DispatchMessage函数的作用是将处理后的消息分派给应用程序,他们的函数原型可以参考MSDN,那儿由详细的介绍。

 

        //处理消息循环

      while( GetMessage(&Msg, NULL, 0, 0) )

       {

             TranslateMessage(&Msg);

             DispatchMessage(&Msg);

       }

 

只有这样,我们的窗口才不会消失,窗口程序才不会结束,可是问题又来了,你说程序不会结束,当我只要一点击关闭按钮程序马上就结束了,这不是与你说的又矛盾吗,其实,并没有矛盾,当你点击窗口的关闭按钮时程序将受到WM_DESTROY消息,而我们又在窗口的回调函数WndProcedure中对它进行了处理,即调用PostQuitMessage(WM_QUIT)函数来结束程序,这个过程之所以会发生就在于每次当程序的窗口受到窗口消息时都会调用它的回调函数来进行处理,只是这儿的处理方式是当受到WM_DESTROY消息时结束程序而已。你可以将处理WM_DESTROY消息的代码注释掉,你看看程序还会不会结束!我的测试结果时它只是关闭了窗口,程序并没有结束,你还可以在任务管理其中看到它!

 

上面的言语只是简单的表达了如何创建一个原生的窗口程序而已,其实那里面还又很多东西要学,如在说处理消息循环时的消息队列,Window 是如何来处理这些消息的等等,这要求读者在以后的学习中慢慢体会,学习!如果你对本程序感兴趣的话可以到http://www.zccfamily.com/zqget/ 网站下载该程序来测试一笑效果.!如果有什么问题的话还可以和我联系,我的Email:zqget123@sina.com

阅读全文
0 0

相关文章推荐

img
取 消
img