Windows程序设计03:创建窗口类

  窗口是位于屏幕中的一个矩形区域,它用于接收用户的输入,然后以文本或图形的形式显示输出。

  那么如何来创建一个窗口呢?可以通过以下五个步骤来完成。

  第一,创建窗口类,用于指定窗口的宏观特性。

  第二,调用RegisterClass函数注册窗口类。

  第三,调用CreateWindow函数创建窗口,用于指定窗口的细节式样。

  第四,调用ShowWindow函数显示窗口,调用UpdateWindow函数更新窗口。

  第五,消息循环,处理窗口过程函数。

  在本篇博文中,将详细介绍如何来创建一个窗口类,也就是上述五个步骤中的第一步,其他几步的实现方法将在后续的博文中一一介绍。 

1.窗口类

  当应用程序在创建窗口时,首先需要注册一个窗口类,用于指定窗口的宏观特性。窗口类为窗口定义了窗口风格、窗口过程、显示和绘制窗口所需要的信息等。

  在winuser.h头文件中定义了窗口类的两种不同形式(ASCII版本的WNDCLASS和Unicode版本的WNDCLASS),如下:

View Code
 1 typedef struct tagWNDCLASSA {
 2     UINT        style;
 3     WNDPROC     lpfnWndProc;
 4     int         cbClsExtra;
 5     int         cbWndExtra;
 6     HINSTANCE   hInstance;
 7     HICON       hIcon;
 8     HCURSOR     hCursor;
 9     HBRUSH      hbrBackground;
10     LPCSTR      lpszMenuName;
11     LPCSTR      lpszClassName;
12 } WNDCLASSA, *PWNDCLASSA, NEAR *NPWNDCLASSA, FAR *LPWNDCLASSA;
13 typedef struct tagWNDCLASSW {
14     UINT        style;
15     WNDPROC     lpfnWndProc;
16     int         cbClsExtra;
17     int         cbWndExtra;
18     HINSTANCE   hInstance;
19     HICON       hIcon;
20     HCURSOR     hCursor;
21     HBRUSH      hbrBackground;
22     LPCWSTR     lpszMenuName;
23     LPCWSTR     lpszClassName;
24 } WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
25 #ifdef UNICODE
26 typedef WNDCLASSW WNDCLASS;
27 typedef PWNDCLASSW PWNDCLASS;
28 typedef NPWNDCLASSW NPWNDCLASS;
29 typedef LPWNDCLASSW LPWNDCLASS;
30 #else
31 typedef WNDCLASSA WNDCLASS;
32 typedef PWNDCLASSA PWNDCLASS;
33 typedef NPWNDCLASSA NPWNDCLASS;
34 typedef LPWNDCLASSA LPWNDCLASS;
35 #endif // UNICODE

  这两个版本的唯一区别在于最后两个结构体数据成员的类型不一样。在ASCII版本中是指向ASCII字符的常量字符串,在Unicode版本中则是指向宽字符的常量字符串。这样做的目的是使程序更容易兼容和扩展,在Charles Petzold的《Windows程序设计》第二章Unicode简介中对这部分内容做了详细的介绍,这里就不再赘述了。

  下面以ASCII版本的WNDCLASS为例对窗口类结构体做一个简单的说明。

1.1定义

  在WinMain中,我们通常用如下形式来定义一个WNDCLASS类型的结构体。

  WNDCLASS wndclass;

  然后对该结构体的10个数据成员进行初始化。

1.2类风格(style)

  WNDCLASS结构体中的数据成员style用于描述类风格。该数据成员可以是“Class styles”的任意组合。“Class styles”在winuser.h头文件中定义如下:

View Code
 1 /*
 2  * Class styles
 3  */
 4 #define CS_VREDRAW          0x0001        //窗口垂直变化,重新绘制窗口
 5 #define CS_HREDRAW          0x0002        //窗口水平变化,重新绘制窗口
 6 #define CS_DBLCLKS          0x0008        //窗口允许两次连续点击
 7 #define CS_OWNDC            0x0020        //每个窗口拥有自己的DC
 8 #define CS_CLASSDC          0x0040        //所有该类型窗口使用同一DC
 9 #define CS_PARENTDC         0x0080        //使用父窗口的DC
10 #define CS_NOCLOSE          0x0200        //系统菜单中没有Close菜单项
11 #define CS_SAVEBITS         0x0800        //保存窗口覆盖区
12 #define CS_BYTEALIGNCLIENT  0x1000        //窗口对齐方式,以8的倍数对齐
13 #define CS_BYTEALIGNWINDOW  0x2000        //窗口客户区对齐方式,以8的倍数对齐
14 #define CS_GLOBALCLASS      0x4000        //表明该窗口类是应用程序的全局类
15 
16 #define CS_IME              0x00010000
17 #if(_WIN32_WINNT >= 0x0501)
18 #define CS_DROPSHADOW       0x00020000    //窗口阴影
19 #endif /* _WIN32_WINNT >= 0x0501 */

  以这种方式定义的标识符称为“位标记”,因为每个标识符都只能影响复合值中的一位,所以可以通过按位或运算(|)进行组合应用。这些类风格中,只有少数会被经常使用。其中,CS_VREDRAW和CS_HREDRAW组合使用,可以指定无论何时窗口的水平尺寸或垂直尺寸被改变,所有基于该窗口类的窗口都将被重新绘制。这样就可以保证绘制在窗口某一位置的文本字符串(或图片)在窗口尺寸改变后仍能保持其相对位置。

1.3窗口过程(lpfnWndProc)

  WNDCLASS结构体中的数据成员lpfnWndProc用于指定该窗口类的窗口过程。窗口过程用于处理传递给所有基于该窗口类创建的窗口的所有消息。关于窗口过程的使用方法将在下一篇博文中详细介绍。

1.4预留空间(cbClsExtra、cbWndExtra)

  WNDCLASS结构体中的数据成员cbClsExtra用于在类结构中预留一些额外的空间。

  WNDCLASS结构体中的数据成员cbWndExtra用于在Windows内部维护的窗口结构中预留一些额外的空间。

1.5应用程序实例句柄(hInstance)

  WNDCLASS结构体中的数据成员hInstance用于指定应用程序的实例句柄。可以直接使用WinMain函数的第一个参数对其赋值即可。

1.6窗口图标句柄(hIcon)

  WNDCLASS结构体中的数据成员hIcon用于指定应用程序的图标式样。当应用程序程序运行时,图标会出现在Window任务栏和程序窗口的标题栏左侧。

  图标是一幅位图格式的小图。可以创建自定义的图标,也可以使用系统预定义的图标。可以通过调用LoadIcon函数来获取系统预定义的图标句柄。

  在winuser.h头文件中定义了LoadIcon函数的原型如下:

View Code
 1 WINUSERAPI
 2 HICON
 3 WINAPI
 4 LoadIconA(
 5     __in_opt HINSTANCE hInstance,
 6     __in LPCSTR lpIconName);
 7 WINUSERAPI
 8 HICON
 9 WINAPI
10 LoadIconW(
11     __in_opt HINSTANCE hInstance,
12     __in LPCWSTR lpIconName);
13 #ifdef UNICODE
14 #define LoadIcon  LoadIconW
15 #else
16 #define LoadIcon  LoadIconA
17 #endif // !UNICODE

  该函数的返回值是HICON(图标句柄),第一个参数为HINSTANCE(实例句柄),即相应程序的实例句柄,第二个参数为LPCSTR,用于标识不同的图标式样。通过第二个参数可以传入系统预定义的图标,这些预定义图标是一些带有IDI前缀的标识符,同样定义在头文件winuser.h中,如下:

View Code
 1 /*
 2  * Standard Icon IDs
 3  */
 4 #ifdef RC_INVOKED
 5 #define IDI_APPLICATION     32512
 6 #define IDI_HAND            32513
 7 #define IDI_QUESTION        32514
 8 #define IDI_EXCLAMATION     32515
 9 #define IDI_ASTERISK        32516
10 #if(WINVER >= 0x0400)
11 #define IDI_WINLOGO         32517
12 #endif /* WINVER >= 0x0400 */
13 #if(WINVER >= 0x0600)
14 #define IDI_SHIELD          32518
15 #endif /* WINVER >= 0x0600 */
16 #else
17 #define IDI_APPLICATION     MAKEINTRESOURCE(32512)
18 #define IDI_HAND            MAKEINTRESOURCE(32513)
19 #define IDI_QUESTION        MAKEINTRESOURCE(32514)
20 #define IDI_EXCLAMATION     MAKEINTRESOURCE(32515)
21 #define IDI_ASTERISK        MAKEINTRESOURCE(32516)
22 #if(WINVER >= 0x0400)
23 #define IDI_WINLOGO         MAKEINTRESOURCE(32517)
24 #endif /* WINVER >= 0x0400 */
25 #if(WINVER >= 0x0600)
26 #define IDI_SHIELD          MAKEINTRESOURCE(32518)
27 #endif /* WINVER >= 0x0600 */
28 #endif /* RC_INVOKED */
29 
30 #if(WINVER >= 0x0400)
31 #define IDI_WARNING     IDI_EXCLAMATION
32 #define IDI_ERROR       IDI_HAND
33 #define IDI_INFORMATION IDI_ASTERISK
34 #endif /* WINVER >= 0x0400 */

  其中常用的一些预定义窗口图标式样如图1所示。

图1 窗口图标系统预定义式样

1.7鼠标指针句柄(hCursor)

  WNDCLASS结构体中的数据成员hCursor用于指定应用程序的鼠标式样。

  通过调用LoadCursor函数可以获取系统预定义的鼠标句柄。在winuser.h头文件中定义了LoadCursor函数的原型如下:

View Code
 1 WINUSERAPI
 2 HCURSOR
 3 WINAPI
 4 LoadCursorA(
 5     __in_opt HINSTANCE hInstance,
 6     __in LPCSTR lpCursorName);
 7 WINUSERAPI
 8 HCURSOR
 9 WINAPI
10 LoadCursorW(
11     __in_opt HINSTANCE hInstance,
12     __in LPCWSTR lpCursorName);
13 #ifdef UNICODE
14 #define LoadCursor  LoadCursorW
15 #else
16 #define LoadCursor  LoadCursorA
17 #endif // !UNICODE

  该函数的返回值是HCURSOR(鼠标句柄),第一个参数为HINSTANCE (实例句柄),即相应程序的实例句柄,第二个参数为LPCSTR ,用于标识不同的鼠标式样。通过第二个参数可以传入系统预定义的鼠标式样,这些预定义鼠标式样是一些带有IDC前缀的标识符,同样定义在头文件winuser.h中,如下:

View Code
 1 /*
 2  * Standard Cursor IDs
 3  */
 4 #define IDC_ARROW           MAKEINTRESOURCE(32512)    //标准箭头光标
 5 #define IDC_IBEAM           MAKEINTRESOURCE(32513)    //I型光标
 6 #define IDC_WAIT            MAKEINTRESOURCE(32514)    //沙漏
 7 #define IDC_CROSS           MAKEINTRESOURCE(32515)    //十字光标
 8 #define IDC_UPARROW         MAKEINTRESOURCE(32516)    //上箭头光标
 9 #define IDC_SIZE            MAKEINTRESOURCE(32640)  /* OBSOLETE: use IDC_SIZEALL */
10 #define IDC_ICON            MAKEINTRESOURCE(32641)  /* OBSOLETE: use IDC_ARROW */
11 #define IDC_SIZENWSE        MAKEINTRESOURCE(32642)    //指向西北和东南方向的箭头光标
12 #define IDC_SIZENESW        MAKEINTRESOURCE(32643)    //指向东北和西南方向的箭头光标
13 #define IDC_SIZEWE          MAKEINTRESOURCE(32644)    //指向东西方向的箭头光标
14 #define IDC_SIZENS          MAKEINTRESOURCE(32645)    //指向南北方向的箭头光标
15 #define IDC_SIZEALL         MAKEINTRESOURCE(32646)    //十字箭头光标
16 #define IDC_NO              MAKEINTRESOURCE(32648) /*not in win3.1 */
17 #if(WINVER >= 0x0500)
18 #define IDC_HAND            MAKEINTRESOURCE(32649)    //手型光标
19 #endif /* WINVER >= 0x0500 */
20 #define IDC_APPSTARTING     MAKEINTRESOURCE(32650) /*not in win3.1 */
21 #if(WINVER >= 0x0400)
22 #define IDC_HELP            MAKEINTRESOURCE(32651)    //带问号的光标
23 #endif /* WINVER >= 0x0400 */

1.8客户区背景色(hbrBackground)

  WNDCLASS结构体中的数据成员hbrBackground用于指定客户区背景色,其数据类型为HBRUSH(画刷句柄)。画刷是一个图形学术语,表示用于区域填充的像素着色模式。

  通过调用GetStockObject函数可以获取系统预定义的“库存”画刷。在头文件winGDI.h中定义了GetStockObject函数的原型如下:

  WINGDIAPI HGDIOBJ WINAPI GetStockObject( __in int i);

  该函数的返回值类型为HGDIOBJ,仅有一个参数i,通过该参数可以传入系统预定义的库存画刷,这些库存画刷同样定义在头文件winGDI.h

中,如下:

View Code
 1 /* Stock Logical Objects */
 2 #define WHITE_BRUSH         0    //白色画刷
 3 #define LTGRAY_BRUSH        1    //亮灰色画刷
 4 #define GRAY_BRUSH          2    //灰色画刷
 5 #define DKGRAY_BRUSH        3    //暗灰色画刷
 6 #define BLACK_BRUSH         4    //黑色画刷
 7 #define NULL_BRUSH          5    //空画刷
 8 #define HOLLOW_BRUSH        NULL_BRUSH
 9 #define WHITE_PEN           6    //白色钢笔
10 #define BLACK_PEN           7    //黑色钢笔
11 #define NULL_PEN            8    //空钢笔
12 #define OEM_FIXED_FONT      10    //原始设备制造商相关固定间距(等宽)字体
13 #define ANSI_FIXED_FONT     11    //在Windows中为固定间距(等宽)系统字体
14 #define ANSI_VAR_FONT       12    //在Windows中为变间距(比例间距)系统字体
15 #define SYSTEM_FONT         13    //系统字体
16 #define DEVICE_DEFAULT_FONT 14    //在WindowsNT中为设备相关字体
17 #define DEFAULT_PALETTE     15    //缺省调色板
18 #define SYSTEM_FIXED_FONT   16    //固定间距(等宽)系统字体

1.9窗口类的菜单(lpszMenuName)

  WNDCLASS结构体中的数据成员lpszMenuName用于指定窗口类的菜单。

1.10窗口类名称(lpszClassName)

  WNDCLASS结构体中的数据成员lpszClassName用于指定窗口类的名称。

 

2.创建自己的窗口类

  学习了窗口类结构体,并了解了结构体中各个数据成员的含义和使用方法之后,就可以创建一个自己的窗口类了,具体方法如下所示:

View Code
 1       static TCHAR szAppName[] = TEXT("HelloWindows");
 2       WNDCLASS wndclass;    
 3       //为窗口类各个数据成员赋值
 4       wndclass.style = CS_HREDRAW | CS_VREDRAW;
 5       wndclass.lpfnWndProc = WndProc;
 6       wndclass.cbClsExtra = 0;
 7       wndclass.cbWndExtra = 0;
 8       wndclass.hInstance = hInstance;
 9       wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
10       wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
11       wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
12       wndclass.lpszMenuName = NULL;
13       wndclass.lpszClassName = szAppName;

  在上述代码中,首先定义了一个字符串“HelloWindows”,用作窗口类的名称。然后定义了一个窗口类wndclass,并为该窗口类wndclass的各个数据成员赋值。其中,语句wndclass.lpfnWndProc = WndProc;指定了窗口类wndclass的窗口过程为WndProc(此处并没有实现该函数方法)。语句wndclass.hInstance = hInstance;指定了窗口类wndclass的实例句柄为hInstance(hInstance是WinMain函数的第一个参数)。

 

 

相关资料:

WNDCLASS类简介

http://zifeiyu520yang.blog.sohu.com/115399630.html

探索Win32系统之窗口类

http://www.moon-soft.com/doc/6744.htm

Win32编程day03 学习笔记

http://www.cnblogs.com/tangzhengyue/archive/2012/08/11/2633933.html

MSDN手册

http://msdn.microsoft.com/en-us/library/windows/desktop/ff729176(v=vs.85).aspx

 

posted @ 2013-01-26 20:33  依旧淡然  阅读(3004)  评论(0编辑  收藏  举报