代码改变世界

C语言Windows程序设计->第四天->详解我的窗口(中)

2012-10-09 19:33  wid  阅读(5986)  评论(1编辑  收藏  举报

对窗口创建的详细解释

============

 

·窗口的注册

  一个窗口的风格, 总是要根据窗口类来决定的, 同时, 窗口类决定了处理窗口消息所使用的函数(窗口过程)。 当定义好窗口类对象并完成对象属性后, 如果想要建立这个窗口必须调用函数RegisterClass来注册窗口类, RegisterClass的函数原型如下:

ATOM RegisterClass(CONST WNDCLASS *lpWndClass);

  该函数只有一个参数, 一个指向一个WNDCLASS结构的指针, 现在, 我们再来看一下WNDCLASS窗口类的结构, 下面是等效定义, 和WINUSER.H中的WNDCLASS效果相同, 但WINUSER.H中是通过定义tagWNDCLASSA(ASCII版本)和tagWNDCLASSW(Unicode版本), 然后进行 :

#ifdef UNICODE
typedef WNDCLASSW WNDCLASS;
typedef PWNDCLASSW PWNDCLASS;
typedef NPWNDCLASSW NPWNDCLASS;
typedef LPWNDCLASSW LPWNDCLASS;
#else
typedef WNDCLASSA WNDCLASS;
typedef PWNDCLASSA PWNDCLASS;
typedef NPWNDCLASSA NPWNDCLASS;
typedef LPWNDCLASSA LPWNDCLASS;
#endif // UNICODE

来实现 WNDCLASS的定义, 在效果上和以下定义是相同的:

typedef struct tagWNDCLASS {
    UINT        style;                 //窗口样式
    WNDPROC     lpfnWndProc;          //回调函数
    int         cbClsExtra;            //窗口类扩展
    int         cbWndExtra;            //窗口实例扩展
    HINSTANCE   hInstance;             //窗口实例句柄
    HICON       hIcon;                 //窗口最小化图标
    HCURSOR     hCursor;               //窗口采用鼠标指针样式
    HBRUSH      hbrBackground;         //窗口背景颜色
    LPCWSTR     lpszMenuName;          //窗口菜单
    LPCWSTR     lpszClassName;         //窗口类名
} WNDCLASS, *PWNDCLASS;

 

在WinMain主函数中, 我们使用WNDCLASS创建了一个窗口类对象:wndclass, 并且对wndclass的属性做了如下设置:

wndclass.style = CS_HREDRAW | CS_VREDRAW ;                         //窗口样式
wndclass.lpszClassName = szAppName ;                               //窗口类名
wndclass.lpszMenuName = NULL ;                                     //窗口菜单:无
wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;    //窗口背景颜色
wndclass.lpfnWndProc = WndProc ;                                   //窗口消息处理函数
wndclass.cbWndExtra = 0 ;                                          //窗口实例扩展:无
wndclass.cbClsExtra = 0 ;                                          //窗口类扩展:无
wndclass.hInstance = hInstance ;                                   //窗口实例句柄
wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;               //窗口最小化图标:使用缺省图标
wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;                 //窗口采用箭头光标

下面我们来详细看下WNDCLASS的这些成员:

  1>. wndclass.style = CS_HREDRAW | CS_VREDRAW ; 

  style属性决定着窗口的风格, 可以通过C语言的或运算组合出不同风格类型的窗口, 在WINUSER.H头文件中定义着这些标识符以及其值, 所有的前缀为CS_的标识符如下:

/*
 * Class styles
 */
#define CS_VREDRAW          0x0001
#define CS_HREDRAW          0x0002
#define CS_DBLCLKS          0x0008
#define CS_OWNDC            0x0020
#define CS_CLASSDC          0x0040
#define CS_PARENTDC         0x0080
#define CS_NOCLOSE          0x0200
#define CS_SAVEBITS         0x0800
#define CS_BYTEALIGNCLIENT  0x1000
#define CS_BYTEALIGNWINDOW  0x2000
#define CS_GLOBALCLASS      0x4000
#define CS_IME              0x00010000

 

  2>. wndclass.lpszClassName = szAppName ;

  赋予窗口一个名称, 可以使用ASCII版本的字符串也可以使用Unicode版本的字符串, 需要注意的是, 这里的窗口名称并不是指窗口标题。

 

  3>. wndclass.lpszMenuName = NULL ; 

  指定窗口类的菜单, 由于我们这个窗口没有使用菜单, 所以为NULL, 具体的用法以后肯定会学习到;

 

  4>. wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;

  窗口的背景颜色, 这里使用的是以白色作为填充, 填充白色这是常见的做法, 如果你愿意, 也可以填充为其他的一些样式, 这里是一些样式的标识符:

 

#define WHITE_BRUSH         0
#define LTGRAY_BRUSH        1
#define GRAY_BRUSH          2
#define DKGRAY_BRUSH        3
#define BLACK_BRUSH         4
#define NULL_BRUSH          5
#define HOLLOW_BRUSH        NULL_BRUSH
#define WHITE_PEN           6
#define BLACK_PEN           7
#define NULL_PEN            8
#define OEM_FIXED_FONT      10
#define ANSI_FIXED_FONT     11
#define ANSI_VAR_FONT       12
#define SYSTEM_FONT         13
#define DEVICE_DEFAULT_FONT 14
#define DEFAULT_PALETTE     15
#define SYSTEM_FIXED_FONT   16

 

 

  5>. wndclass.lpfnWndProc = WndProc ; 

  将窗口的消息处理函数设置为我们自定义的WndProc函数。

 

  6>. wndclass.cbWndExtra = 0 ; 

  7>. wndclass.cbClsExtra = 0 ;

  这两个属性用来维护结构中预留的一些额外空间, 程序可以根据需要要使用这些额外空间, 通过匈牙利命名的cbClsExtra、cbWndExtra中的cb可以知道, 这些成员表示一个"字节数", 由于我们这个窗口没有使用到额外空间, 所以将这个两个属性赋值为0;

 

  8>. wndclass.hInstance = hInstance ;

  表示应用程序的实例句柄,  hInstance的来源是WinMain的一个参数;

 

  9>. wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;

  加载一个位图作为程序标题栏最左侧的小图标, 我们这里加载了一个系统的默认图标, 后面的学习这将会学习到如何从磁盘加载我们自定义的图标.

 

  10>. wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ; 

  与LoadIcon类似, 加载鼠标的指针位图;

 

完成这是个窗口类成员属性的初始化后, 我们就可以通过RegisterClass来注册窗口了, 如果注册成功, 将返回一个具有唯一标识已注册的类的一个原子, 如果函数失败,返回0。

 

 

 

 

·窗口的创建

  成功注册窗口类后, 我们就可以呼叫CreateWindow函数对窗口进行创建了, CreateWindow函数的原型如下:

 

HWND CreateWindow(
  LPCTSTR lpClassName,               //窗口类名称
  LPCTSTR lpWindowName,              //窗口标题
  DWORD dwStyle,                     //窗口样式
  int x,                             //窗口初始x坐标
  int y,                             //窗口初始y坐标
  int nWidth,                        //窗口初始x方向尺寸
  int nHeight,                       //窗口初始y方向尺寸
  HWND hWndParent,                   //父窗口句柄
  HMENU hMenu,                       //窗口菜单句柄
  HANDLE hlnstance,                  //程序实例句柄
  LPVOID lpParam                     //创建参数
);

 

函数返回的是创建成功后的窗口的句柄。 需要说明的几点:

  1>.参数一: LPCTSTR  lpClassName

  参数LPCTSTR lpClassName,为窗口的名称, 我们需要传入的参数就是刚才我们在窗口类注册的窗口类名称, 这样使用CreateWindow建立的窗口就能与注册的窗口进行关联。

 

  2>. 参数三: DWORD dwStyle

  参数三为窗口的样式, 示例中创建的是一个普通的层叠窗口样式, WS_OVERLAPPEDWINDOW, 打开WINUSER.H头文件, 对于WS_OVERLAPPEDWINDOW是这样定义的:

#define WS_OVERLAPPEDWINDOW (WS_OVERLAPPED     | \
                             WS_CAPTION        | \
                             WS_SYSMENU        | \
                             WS_THICKFRAME     | \
                             WS_MINIMIZEBOX    | \
                             WS_MAXIMIZEBOX)

可以看出, WS_OVERLAPPEDWINDOW样式实际上是通过一些标识符通过或的组合, 此外我们还可以通过组合设计我们自己的样式, 这些标识符在WINUSER.H的定义如下:

#define WS_OVERLAPPED       0x00000000L            //产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。 
#define WS_POPUP            0x80000000L            //创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。 
#define WS_CHILD            0x40000000L            //创建一个子窗口。这个风格不能与WS_POPUP风格合用。 
#define WS_MINIMIZE         0x20000000L            //创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。
#define WS_VISIBLE          0x10000000L            //创建一个最初可见的窗口。
#define WS_DISABLED         0x08000000L            //创建一个初始状态为禁止的窗口。
#define WS_CLIPSIBLINGS     0x04000000L            //排除子窗口之间的相对区域。
#define WS_CLIPCHILDREN     0x02000000L            //创建一个初始状态为禁止的子窗口。一个禁止状态的窗口不能接受来自用户的输入信息。 
#define WS_MAXIMIZE         0x01000000L            //创建一个初始状态为最大化状态的窗口。 
#define WS_CAPTION          0x00C00000L            //创建一个有标题框的窗口(包括WS_BODER风格)。 
#define WS_BORDER           0x00800000L            //创建一个单边框的窗口。 
#define WS_DLGFRAME         0x00400000L            //创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。 
#define WS_VSCROLL          0x00200000L            //创建一个有垂直滚动条的窗口。 
#define WS_HSCROLL          0x00100000L            //创建一个有水平滚动条的窗口。 
#define WS_SYSMENU          0x00080000L            //创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。 
#define WS_THICKFRAME       0x00040000L            //创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。 
#define WS_GROUP            0x00020000L            //指定一组控制的第一个控制。
#define WS_TABSTOP          0x00010000L            //创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。 
#define WS_MINIMIZEBOX      0x00020000L            //创建一个具有最小化按钮的窗口。
#define WS_MAXIMIZEBOX      0x00010000L            //创建一个具有最大化按钮的窗口。
#define WS_TILED            WS_OVERLAPPED          //产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。
#define WS_ICONIC           WS_MINIMIZE            //创建一个初始状态为最小化的窗口。仅与WS_OVERLAPPED风格一起使用。
#define WS_SIZEBOX          WS_THICKFRAME          //创建一个具有厚边框的窗口,可以通过厚边框来改变窗口大小。
#define WS_TILEDWINDOW      WS_OVERLAPPEDWINDOW    //创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU,WS_THICKFRAME,WS_MINIMIZEBOX和WS_MAXIMIZEBOX风格的重叠式窗口。

关于这些样式的详细说明可以查阅MSDN Library(推荐)或到百科查询。

 

 

·窗口的显示

  使用CreateWindow函数成功创建好窗口后, 这个窗口就被在保存在一段内存中了, 但是此时窗口还不能显示在屏幕上, 我们需要使用ShowWindow函数来将建立好的窗口显示出来, ShowWindow函数的原型如下:

BOOL ShowWindow( HWND hWnd, int iCmdShow );

参数一为刚才通过CreateWindow函数窗口出的窗口句柄, 参数二为窗口的显示方式, 由WinMain函数的int iCmdShow接收该值, 常用的显示方式有:

SW_HIDE                        //隐藏窗口并激活其他窗口;
SW_MAXIMIZE                    //最大化;
SW_MINIMIZE                    //最小化指定的窗口并且激活在Z序中的下一个顶层窗口;
SW_RESTORE                     //激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置;
SW_SHOW                        //在窗口原来的位置以原来的尺寸激活和显示窗口;
SW_SHOWMAXIMIZED               //激活窗口并将其最大化;
SW_SHOWMINIMIZED               //激活窗口并将其最小化;
SW_SHOWMINNOACTIVE             //窗口最小化,激活窗口仍然维持激活状态;
SW_SHOWNA
//以窗口原来的状态显示窗口。激活窗口仍然维持激活状态; SW_SHOWNOACTIVATE //以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态;   SW_SHOWNORMAL //激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小;

 

 

 

·窗口的更新

 

当窗口客户区需要进行更新时, UpdateWindow函数就会被调用, 并绕过消息队列直接发送一个WM_PAINT的消息给窗口过程函数WndProc进行相应处理, UpdateWindow函数的原型如下:

 

BOOL UpdateWindow( HWND hWnd  );

 

该函数只有一个参数, 参数为需要更新的窗口句柄; 函数调用成功返回值为非0, 调用失败时返回值为0。

 

明天学习窗口过程WndProc是如何处理这些消息的。


--------------------

 

Wid, 2012.10.09

 

 上一篇: C语言Windows程序设计->第四天->详解我的窗口(上)