代码改变世界

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

2012-10-09 11:50  wid  阅读(6955)  评论(1编辑  收藏  举报

对窗口创建的详细解释

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

  在昨天的学习中我们已经初步完成了一个窗口的创建虽然我们对于代码中的许多语句可能还不理解但这暂时并不会影响到我们的学习再次来回顾昨天那个窗口的代码部分:

Create myWindow - View Code
 1 #include <windows.h>
 2 
 3 LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ;        //声明用来处理消息的函数
 4 
 5 int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )
 6 {
 7     static TCHAR szAppName[] = TEXT("MyWindow") ;
 8     HWND hwnd ;
 9     MSG msg ;
10     WNDCLASS wndclass ;        //声明一个窗口类对象
11 
12     //以下为窗口类对象wndclass的属性
13     wndclass.style = CS_HREDRAW | CS_VREDRAW ;                         //窗口样式
14     wndclass.lpszClassName = szAppName ;                               //窗口类名
15     wndclass.lpszMenuName = NULL ;                                     //窗口菜单:无
16     wndclass.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH) ;    //窗口背景颜色
17     wndclass.lpfnWndProc = WndProc ;                                   //窗口处理函数
18     wndclass.cbWndExtra = 0 ;                                          //窗口实例扩展:无
19     wndclass.cbClsExtra = 0 ;                                          //窗口类扩展:无
20     wndclass.hInstance = hInstance ;                                   //窗口实例句柄
21     wndclass.hIcon = LoadIcon( NULL, IDI_APPLICATION ) ;               //窗口最小化图标:使用缺省图标
22     wndclass.hCursor = LoadCursor( NULL, IDC_ARROW ) ;                 //窗口采用箭头光标
23 
24     if( !RegisterClass( &wndclass ) )
25     {    //注册窗口类, 如果注册失败弹出错误提示
26         MessageBox( NULL, TEXT("窗口注册失败!"), TEXT("错误"), MB_OK | MB_ICONERROR ) ;
27         return 0 ;
28     }
29 
30     hwnd = CreateWindow(                   //创建窗口
31                 szAppName,                 //窗口类名
32                 TEXT("我的窗口"),           //窗口标题
33                 WS_OVERLAPPEDWINDOW,       //窗口的风格
34                 CW_USEDEFAULT,             //窗口初始显示位置x:使用缺省值
35                 CW_USEDEFAULT,             //窗口初始显示位置y:使用缺省值
36                 CW_USEDEFAULT,             //窗口的宽度:使用缺省值
37                 CW_USEDEFAULT,             //窗口的高度:使用缺省值
38                 NULL,                      //父窗口:无
39                 NULL,                      //子菜单:无
40                 hInstance,                 //该窗口应用程序的实例句柄 
41                 NULL                       //
42             ) ;
43 
44     ShowWindow( hwnd, iCmdShow ) ;        //显示窗口
45     UpdateWindow( &msg );                 //更新窗口
46 
47     while( GetMessage( &msg, NULL, 0, 0 ) )        //从消息队列中获取消息
48     {
49         TranslateMessage( &msg ) ;                 //将虚拟键消息转换为字符消息
50         DispatchMessage( &msg ) ;                  //分发到回调函数(过程函数)
51     }
52     return msg.wParam ;
53 }
54 
55 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
56 {
57     HDC hdc ;                //设备环境句柄
58     PAINTSTRUCT ps ;         //绘制结构
59     RECT rect;               //矩形结构
60 
61     switch( message )        //处理得到的消息
62     {
63     case WM_CREATE:          //窗口创建完成时发来的消息
64         MessageBox( hwnd, TEXT("窗口已创建完成!"), TEXT("我的窗口"), MB_OK | MB_ICONINFORMATION ) ;
65         return 0;
66 
67     case WM_PAINT:           //处理窗口区域无效时发来的消息
68         hdc = BeginPaint( hwnd, &ps ) ;
69         GetClientRect( hwnd, &rect ) ;
70         DrawText( hdc, TEXT( "Hello, 这是我自己的窗口!" ), -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER ) ;
71         EndPaint( hwnd, &ps ) ;
72         return 0 ;
73 
74     case WM_LBUTTONDOWN:     //处理鼠标左键被按下的消息
75         MessageBox( hwnd, TEXT("鼠标左键被按下。"), TEXT("单击"), MB_OK | MB_ICONINFORMATION ) ;
76         return 0;
77 
78     case WM_DESTROY:         //处理窗口关闭时的消息
79         MessageBox( hwnd, TEXT("关闭程序!"), TEXT("结束"), MB_OK | MB_ICONINFORMATION ) ;
80         PostQuitMessage( 0 ) ;
81         return 0;
82     }
83     return DefWindowProc( hwnd, message, wParam, lParam ) ;        //DefWindowProc处理我们自定义的消息处理函数没有处理到的消息
84 }

 

·调用了哪些Windows API

  通过这段代码我们完成了在客户区(窗口的白色区域)中心显示一段字符串此外我们还处理了系统发来的部分消息在这个过程中我们使用了Windows的诸多函数这些函数分别为:

 

函数名 函数描述

GetStockObject

获取一个图形对象

LoadIcon

为程序加载图标

LoadCursor

为程序加载光标

RegisterClass

为程序窗口注册一个窗口类

MessageBox

显示消息对话框

CreateWindow

创建一个窗口

ShowWindow

在屏幕上将窗口显示出来

UpdateWindow

重绘窗口客户区

GetMessage

从消息队列获取消息

TranslateMessage

将虚拟键消息转换为字符消息

DispatchMessage

将消息发送给消息处理函数

BeginPaint

准备对窗口进行绘图

GetClientRect

获取窗口客户区尺寸

DrawText

绘制一个文本字符串

EndPaint

结束对窗口的绘图

PostQuitMessage

向消息队列插入"退出"消息 

DefWindowProc

执行系统默认的消息处理 

 

对于这些函数的详细说明, 可以到百科查询, 或者到MSDN Library文档中查询(推荐)。

 

 

·大写标识符说明

  在上面的程序中出现了许多类似于XX_XXXX的大写标识符:

 

CS_HREDRAW

CS_VREDRAW

IDI_APPLICATION

IDC_ARROW

MB_OK

MB_ICONERROR

WS_OVERLAPPEDWINDOW

CW_USEDEFAULT

DT_SINGLELINE

DT_CENTER

DT_VCENTER

WM_CREATE

WM_PAINT

WM_LBUTTONDOWN

WM_DESTROY

 

这些标识符均为数值常量WINUSER.H头文件中有定义该程序中用到的一些标识符前缀含义为:

前缀

含义

CS_

类风格选项

CW_

创建窗口选项

DT_

文本绘制选项

IDI_

图标的ID

IDC_

光标的ID

MB_

消息框选项

WM_

窗口消息

WS_

窗口风格

 

 

对于这些大写标识符暂时没必要强记下来只需要对其有个大致的印象即可不会影响到我们的学习。

 

 

·""数据类型

  在调用的函数中一些函数的参数类型是我们以往在C控制台编程中所没有见到过的例如在代码的第三行对回调函数的声明中:

 

LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ) ; //声明用来处理消息的函数

 

其中的"LRESULT""UINT""WPARAM""LPWARAM", 以及主函数WinMain中的"PSTR"之类的类型都是我们所没有见过的这些""数据类型都是什么呢?

 

其实这些""数据类型是为了程序书写时的简便而使用typedef#defineC已有的数据类型重新定义的WINDEF.H/WINNT.H头文件中有定义:

 

typedef unsigned int UINT;
typedef char CHAR;
typedef CHAR *LPSTR, *PSTR;
typedef UINT WPARAM;
typedef long LONG;
typedef LONG LPARAM;
typedef LONG LRESULT;

 

可以看出, UINT实际上就是unsigned int; PSTR就是一个char *, WPARAM被定义为UINT也就是unsigned int; LPARAMLRESULT被定义为long;

 

由此观之, ""数据类型并不新。

 

在声明消息处理函数WndProc在函数名前面我们还是使用了一个"CALLBACK"标识符这个标识符其实就是函数的调用规则WINDEF.H中有定义:

 

#define CALLBACK    __stdcall

 

在前些天的学习中我们还知道在WinMain主函数的前面有个WINAPI调用规则WINDEF.H中也被定义为 __stdcall

 

 

 

·结构类型

  结构体C语言的学习中我们已经对这种数据类型十分熟悉了在上述创建窗口的过程中我们使用了四种结构类型来创建结构体的对象这些结构体在WINUSER.H/WINDEF.H中有定义现在我们只需对其进行一下印象中的认识对于结构体的成员暂时不去讨论这四种结构体分别为:

 

1>. MSG消息结构

 

MSGWINUSER.H中的定义:

 

typedef struct tagMSG {
    HWND        hwnd;
    UINT        message;
    WPARAM      wParam;
    LPARAM      lParam;
    DWORD       time;
    POINT       pt;
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

 

 

2>. WNDCLASS窗口类结构

WNDCLASSWINUSER.H中的定义:

 

typedef struct tagWNDCLASSW {
    UINT        style;
    WNDPROC     lpfnWndProc;
    int         cbClsExtra;
    int         cbWndExtra;
    HINSTANCE   hInstance;
    HICON       hIcon;
    HCURSOR     hCursor;
    HBRUSH      hbrBackground;
    LPCWSTR     lpszMenuName;
    LPCWSTR     lpszClassName;
} WNDCLASSW, *PWNDCLASSW, NEAR *NPWNDCLASSW, FAR *LPWNDCLASSW;
#ifdef UNICODE
typedef WNDCLASSW WNDCLASS;

 

 

3>. PAINTSTRUCT绘制结构

PAINTSTRUCTWINUSER.H中的定义:

 

typedef struct tagPAINTSTRUCT {
    HDC         hdc;
    BOOL        fErase;
    RECT        rcPaint;
    BOOL        fRestore;
    BOOL        fIncUpdate;
    BYTE        rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT, *NPPAINTSTRUCT, *LPPAINTSTRUCT;

 

 

4>. RECT矩形结构

RECTWINDEF.H中的定义:

typedef struct tagRECT
{
    LONG    left;
    LONG    top;
    LONG    right;
    LONG    bottom;
} RECT, *PRECT, NEAR *NPRECT, FAR *LPRECT;

 

 

 

·再谈句柄

  不同类型的句柄有不同的标识符在我们尝试创建窗口的代码中用到的句柄有:

标识符

含义

HINSTANCE

实例句柄指程序本身

HWND

窗口句柄

HDC

设备环境句柄

HBRUSH

图形画刷句柄

 

  句柄是一个标识符,用来来标识对象, 一个句柄使用四个字节长的整数来存储一个整数值这个具体的整数值实际上我们并不需要知道是多少我们要做的就是传递句柄, Windows会知道如果用过这个句柄找到并以引用相应的对象。

 

 

 

·匈牙利命名法

  匈牙利命名法是一种编程时的命名规范, 在一开始我们接触的MessageBox对话框时我们就已经见到了匈牙利命名的变量:

int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow )

这里的 hInstancehPrevInstanceszCmdLineiCmdShow的命名都遵循匈牙利命名法匈牙利命名法的目的和作用是使变量名非常清晰易懂,增强了代码的可读性,方便各程序员之间相互交流代码, 减少代码中因数据类型不匹配的错误

例如:

 

szCmdLine, 通过变量名我们就可以知道这是一个"0结束的字符串"; 

 

hInstance, h开头代表一个句柄;

 

iCmdShow, i开头代表一个int整形。

 

这样就可以不用再去找到变量声明的位置去看它的变量类型避免了在使用变量时由于数据类型不匹配引起的错误。

 

经常使用的匈牙利命名的前缀如下:

 

前缀

含义描述

p 指针
fn 函数
v  无效
h 句柄
l 长整形
b 布尔型
f 浮点型
dw 双字
sz 字符串
n 短整型
d 双精度浮点型
c 计数, 通常写为cnt
ch 字符, 通常写为c
i 整型
by 字节
w 字型
r 实型
u 无符号型
   
g_ 全局变量
c_ 常量
m_ 成员变量
s_ 静态变量
   
Max 最大
Min 最小
Init 初始化
T 或 Temp 临时变量
Src 源对象
Dest 目标对象

 

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