
我们利用一个简单的MessageBox函数创建了一个消息框,但消息框只是Win32中的一个简单的窗口模式,如果要做游戏或者开发应用软件的话,这个消息框是远远不够的。这就需要我们创建一个功能更强大的窗口。
事实上,如果我们在创建项目的时候不选择” a simple Win32 application”而是选择” a Win32 application”的话,系统就会给我们直接创建好一个能够满足我们需要的窗口程序,但是为了便于理解,我们仍然以上一章的程序作为框架来自己创建这个窗口程序。
在我们创建窗口之前,我们有必要告诉系统我们需要创建一个什么样的窗口,然后再给我们的窗口模式起一个名字,这样系统才能够以我们的标准来为我们创建窗口。这个过程称为“注册窗口类”。为了完成这个过程,Win32API提供了一个结构体WNDCLASSEX(WNDCLASSEX是后期版本对WNDCLASS的扩展)及一个函数RegisterClassEx(带有Ex的都是后期版本对以前的扩展)。WNDCLASSEX是一个API提供给我们的一个用来描述窗口类属性的结构体,他的原形如下:
WNDCLASSEX {
UINT cbSize;
UINT style;
WNDPROC lpfnWndProc;
int cbClsExtra;
int cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCSTR lpszMenuName;
LPCSTR lpszClassName;
HICON hIconSm;
};
其中:
UINT cbSize;用来保存自身结构体的大小。
UINT style;用来描述窗口的类风格。它往往是由一些基本的风格通过二进制的按位或(操作符"|")组合而成。下表列出了一些常用的基本窗口风格:
|
风格 |
含义 |
|
CS_HREDRAW |
如果窗口宽度发生改变,重绘整个窗口 |
|
CS_VREDRAW |
如果窗口高度发生改变,重绘整个窗口 |
|
CS_DBLCLKS |
能感受用户在窗口中的双击消息 |
|
CS_NOCLOSE |
禁用系统菜单中的"关闭"命令 |
|
CS_SAVEBITS |
把被窗口遮掩的屏幕图像部分作为位图保存起来。当该窗口被移动时,Windows使用被保存的位图来重建屏幕图像 |
WNDPROC lpfnWndProc;用来处理消息的回调函数。该参数为一个函数指针,回调机制是一种自动调用机制,即当满足函数的调用条件时,由系统自动调用函数。
int cbClsExtra;扩展参数,设为0即可。
int cbWndExtra;扩展参数,设为0即可。
HINSTANCE hInstance; 是窗口所对应的应用程序的句柄,表明该窗口与此应用程序是相关联的。
HICON hIcon;图标资源句柄。我们可以利用资源文件及相关的API函数LoadIcon为我们的窗口类设定一个图标。在Win32API中所有以H开头的数据类型都是句柄。LoadIcon函数的声明格式为:
HICON LoadIcon(HINSTANCE hInstance, LPCTSTR lpIconName);
第一个参数设为NULL表示使用标准的图标。
HCURSOR hCursor;光标资源句柄。光标即当鼠标移动到窗口中时的显示方式,我们经常见到的箭头形状的光标就是系统定义好的光标中的一种。如果需要改变光标的形状,可以利用API函数LoadCursor更换我们的光标。该函数的声明格式如下:
HCURSOR LoadCursor ( HINSTANCE hInst,LPCSTR lpszName);
第一个参数设为NULL表示使用标准的光标形状。API为我们定义了如下几个标准的光标形状:
IDC_ARROW 标准箭头
IDC_APPSTARTING 标准箭头标和小沙漏标
IDC_CROSS 横标线
IDC_IBEAM 文本I 型标
IDC_NO 带正斜线的圆圈
IDC_SIZEALL 四向箭头
IDC_UPARROW 垂直方向的箭头
IDC_WAIT 沙漏
HBRUSH hbrBackground;代表了我们创建的窗口的背景色。可以通过API函数CreateSolidBrush来自己定义窗口的背景颜色。CreateSolidBrush是一个创建画刷的函数,该函数我们会在以后绘图的章节中予以讲解。
LPCSTR lpszMenuName;菜单资源名称字符串。可以把资源项中的菜单资源ID转换为LPCSTR类型,然后通过该参数将该值赋予lpszMenuName成员变量,这样具有该窗口类风格的窗口都将带有一个指定的菜单(窗口的菜单也可以在创建窗口的时候指定)。
LPCSTR lpszClassName;窗口的类名称。即用来描述我们刚刚创建的窗口类风格的字符串,这样我们在注册窗口类以后就可以利用这个字符串创建具有该窗口类风格的窗口。
HICON hIconSm;窗口的小图标资源句柄。是HICON hIcon;的缩小版。
完成上述对结构体WNDCLASSEX对象赋值的过程之后,我们就可以利用API函数RegisterClass(or RegisterClassEx)来注册窗口类,该函数的功能就是将WNDCLASSEX对象描述的窗口属性注册为lpszClassName字符串代表的窗口类,将来我们需要创建该风格的窗口时,就可以指定窗口的类名称为lpszClassName字符串,这样创建出来的窗口就具有刚注册的窗口类的属性。
注册完窗口类之后,我们就可以利用Win32API中的CreateWindow(or CreateWindowEx)函数来创建我们所需要的窗口了。该函数的声明为:
HWND CreateWindow(
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
};
其中:
LPCTSTR lpClassName是创建该窗口所使用的窗口类的名称,注意这个名称应与前面所注册的窗口类的名称一致。
LPCTSTR lpWindowName 窗口标题名称。该名称将显示在你所创建的窗口的标题栏上。
DWORD dwStyle 窗口的风格。常用的窗口风格如下:
WS_BORDER:创建一个单边框的窗口。
WS_CAPTION:创建一个有标题框的窗口(包括WS_BODER风格)。
WS_CHIlD:创建一个子窗口。这个风格不能与WS_POPVP风格合用。
WS_CHLDWINDOW:与WS_CHILD相同。
WS_CLIPCHILDREN:当在父窗口内绘图时,排除子窗口区域。在创建父窗口时使用这个风格。
WS_CLlPBLINGS;排除子窗口之间的相对区域,也就是,当一个特定的窗口接收到WM_PAINT消息时,WS_CLIPSIBLINGS 风格将所有层叠窗口排除在绘图之外,只重绘指定的子窗口。如果未指定WS_CLIPSIBLINGS风格,并且子窗口是层叠的,则在重绘子窗口的客户区时,就会重绘邻近的子窗口。
WS_DISABLED:创建一个初始状态为禁止的子窗口。一个禁止状态的窗日不能接受来自用户的输人信息。
WS_DLGFRAME:创建一个带对话框边框风格的窗口。这种风格的窗口不能带标题条。
WS_GROUP:指定一组控制的第一个控制。这个控制组由第一个控制和随后定义的控制组成,自第二个控制开始每个控制,具有WS_GROUP风格,每个组的第一个控制带有WS_TABSTOP风格,从而使用户可以在组间移动。用户随后可以使用光标在组内的控制间改变键盘焦点。
WS_HSCROLL:创建一个有水平滚动条的窗口。
WS_ICONIC:创建一个初始状态为最小化状态的窗口。与WS_MINIMIZE风格相同。
WS_MAXIMIZE:创建一个具有最大化按钮的窗口。该风格不能与WS_EX_CONTEXTHELP风格同时出现,同时必须指定WS_SYSMENU风格。
WS_OVERLAPPED:产生一个层叠的窗口。一个层叠的窗口有一个标题条和一个边框。与WS_TILED风格相同。
WS_OVERtAPPEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU WS_THICKFRAME,WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口,与WS_TILEDWINDOW风格相同。
WS_POPUP;创建一个弹出式窗口。该风格不能与WS_CHLD风格同时使用。
WS_POPUWINDOW:创建一个具有WS_BORDER,WS_POPUP,WS_SYSMENU风格的窗口,WS_CAPTION和WS_POPUPWINDOW必须同时设定才能使窗口某单可见。
WS_SIZEBOX:创建一个可调边框的窗口,与WS_THICKFRAME风格相同。
WS_SYSMENU:创建一个在标题条上带有窗口菜单的窗口,必须同时设定WS_CAPTION风格。
WS_TABSTOP:创建一个控制,这个控制在用户按下Tab键时可以获得键盘焦点。按下Tab键后使键盘焦点转移到下一具有WS_TABSTOP风格的控制。
WS_THICKFRAME:创建一个具有可调边框的窗口,与WS_SIZEBOX风格相同。
WS_TILED:产生一个层叠的窗口。一个层叠的窗口有一个标题和一个边框。与WS_OVERLAPPED风格相同。
WS_TILEDWINDOW:创建一个具有WS_OVERLAPPED,WS_CAPTION,WS_SYSMENU MS_THICKFRAME.
WS_MINIMIZEBOX,WS_MAXMIZEBOX风格的层叠窗口。与WS_OVERLAPPEDWINDOW风格相同。
WS_VISIBLE:创建一个初始状态为可见的窗口。WS_VSCROLL:创建一个有垂直滚动条的窗口。
如果需要多个窗口风格,可以将自己需要的风格用”|”或在一起。在DirectX编程中,我们一般使用的是WS_POPUP | WS_MAXIMIZE,用这个标志创建的窗口没有标题栏和系统菜单且窗口为最大化,可以充分满足DirectX编程的需要。CreateWindowEx函数比CreateWindow函数多了一个DWORD dwExStyle参数,该参数代表了一些后来API提供的一些窗口的扩展风格。如WS_EX_ACCEPTFILES等。
X:指定窗口的初始水平位置。对一个层叠或弹出式窗口,X参数是屏幕坐标系的窗口的左上角的初始X坐标。对于子富口,x是子窗口左上角相对父窗口客户区左上角的初始X坐标。如果该参数被设为CW_UCEDEFAULT则系统为窗口选择缺省的左上角坐标并忽略Y参数。CW_USEDEFAULT只对层叠窗口有效,如果为弹出式窗口或子窗口设定,则X和y参数被设为零。
Y:指定窗口的初始垂直位置。对一个层叠或弹出式窗日,y参数是屏幕坐标系的窗口的左上角的初始y坐标。对于子窗口,y是子窗口左上角相对父窗口客户区左上角的初始y坐标。对于列表框,y是列表框客户区左上角相对父窗口客户区左上角的初始y坐标。如果层叠窗口是使用WS_VISIBLE风格位创建的并且X参数被设为CW_USEDEFAULT,则系统将忽略y参数。
nWidth:以设备单元指明窗口的宽度。对于层叠窗口,nWidth或是屏幕坐标的窗口宽度或是CW_USEDEFAULT。若nWidth是CW_USEDEFAULT,则系统为窗口选择一个缺省的高度和宽度:缺省宽度为从初始X坐标开始到屏幕的右边界,缺省高度为从初始X坐标开始到目标区域的顶部。CW_USEDFEAULT只参层叠窗口有效;如果为弹出式窗口和子窗口设定CW_USEDEFAULT标志则nWidth和nHeight被设为零。
nHelght:以设备单元指明窗口的高度。对于层叠窗口,nHeight是屏幕坐标的窗口宽度。若nWidth被设为CW_USEDEFAULT,则系统忽略nHeight参数。
HWND hWndParent指示该窗口的父窗口句柄。
HMENU hMenu表示窗口的菜单资源句柄。如果想要基于这个参数给窗口添加菜单,我们就可以把菜单资源项句柄通过这个参数传给CreateWindow函数,这样创建出来的窗口就会带有指定的菜单。菜单相关函数我们将在后面的章节里讲述。对于子窗口,hMenu指定了该子窗口标识(一个整型量),一个对话框使用这个整型值将事件通知父类。应用程序确定子窗口标识,这个值对于相同父窗口的所有子窗口必须是唯一的。
HINSTANCE hInstance为创建该窗口的应用程序实例句柄。
lpParam:指向一个值的指针,该值传递给窗口 WM_CREATE消息。该值通过在IParam参数中的CREATESTRUCT结构传递。如果应用程序调用CreateWindow创建一个MDI客户窗口,则lpParam必须指向一个CLIENTCREATESTRUCT结构。
如果窗口创建成功,CreateWindow返回新窗口的句柄,否则返回NULL, 若想获得更多错误信息,请调用GetLastError函数。
我们可以定义一个HWND类型的变量来接收CreateWindow函数的返回值,以后我们就可以利用该窗口句柄变量来操作该窗口。
CreateWindowEx函数是CreateWindow函数的扩展版本,其原形如下:
HWND CreateWindowEx(
DWORD dwExStyle,
LPCTSTR lpClassName,
LPCTSTR lpWindowName,
DWORD dwStyle,
int x,
int y,
int nWidth,
int nHeight,
HWND hWndParent,
HMENU hMenu,
HINSTANCE hInstance,
LPVOID lpParam
};
该函数比CreateWindow函数多了一个参数,即第一个参数,该参数表示了CreateWindowEx函数所提供的窗口的扩展风格,常用有如下扩展风格:
WS_EX_ACCEPTFILES:指定以该风格创建的窗口接受一个拖拽文件。
WS_EX_APPWINDOW:当窗口可见时,将一个顶层窗口放置到任务条上。
WS_EX_CLIENTEDGE:指定窗口有一个带阴影的边界。
WS_EX_CONTEXTHELP:在窗口的标题条包含一个问号标志。当用户点击了问号时,鼠标光标变为一个问号的指针、如果点击了一个子窗口,则子窗口接收到WM_HELP消息。子窗口应该将这个消息传递给父窗口过程,父窗口再通过HELP_WM_HELP命令调用WinHelp函数。这个Help应用程序显示一个包含子窗口帮助信息的弹出式窗口。 WS_EX_CONTEXTHELP不能与WS_MAXIMIZEBOX和WS_MINIMIZEBOX同时使用。
WS_EX_CONTROLPARENT:允许用户使用Tab键在窗口的子窗口间搜索。
WS_EX_DLGMODALFRAME:创建一个带双边的窗口;该窗口可以在dwStyle中指定WS_CAPTION风格来创建一个标题栏。
WS_EX_LEFT:窗口具有左对齐属性,这是缺省设置的。
WS_EX_LEFTSCROLLBAR:如果外壳语言是如Hebrew,Arabic,或其他支持reading order alignment的语言,则标题条(如果存在)则在客户区的左部分。若是其他语言,在该风格被忽略并且不作为错误处理。
WS_EX_LTRREADING:窗口文本以LEFT到RIGHT(自左向右)属性的顺序显示。这是缺省设置的。
WS_EX_MDICHILD:创建一个MD子窗口。
WS_EX_NOPATARENTNOTIFY:指明以这个风格创建的窗口在被创建和销毁时不向父窗口发送WM_PARENTNOTFY消息。
WS_EX_OVERLAPPED:WS_EX_CLIENTEDGE和WS_EX_WINDOWEDGE的组合。
WS_EX_PALETTEWINDOW:WS_EX_WINDOWEDGE, WS_EX_TOOLWINDOW和WS_WX_TOPMOST风格的组合WS_EX_RIGHT:窗口具有普通的右对齐属性,这依赖于窗口类。只有在外壳语言是如Hebrew,Arabic或其他支持读顺序对齐(reading order alignment)的语言时该风格才有效,否则,忽略该标志并且不作为错误处理。
WS_EX_RIGHTSCROLLBAR:垂直滚动条在窗口的右边界。这是缺省设置的。
WS_EX_RTLREADING:如果外壳语言是如Hebrew,Arabic,或其他支持读顺序对齐(reading order alignment)的语言,则窗口文本是一自左向右)RIGHT到LEFT顺序的读出顺序。若是其他语言,在该风格被忽略并且不作为错误处理。
WS_EX_STATICEDGE:为不接受用户输入的项创建一个三维边界风格
WS_EX_TOOLWIDOW:创建工具窗口,即窗口是一个游动的工具条。工具窗口的标题条比一般窗口的标题条短,并且窗口标题以小字体显示。工具窗口不在任务栏里显示,当用户按下alt+Tab键时工具窗口不在对话框里显示。如果工具窗口有一个系统菜单,它的图标也不会显示在标题栏里,但是,可以通过点击鼠标右键或Alt+Space来显示菜单。
WS_EX_TOPMOST:指明以该风格创建的窗口应放置在所有非最高层窗口的上面并且停留在其上,即使窗口未被激活。可以使用函数SetWindowPos来设置和移去这个风格。
WS_EX_TRANSPARENT:指定以这个风格创建的窗口在窗口下的同属窗口已重画时,该窗口才可以重画。
由于其下的同属窗口已被重画,该窗口是透明的。
到此我们的窗口就创建成功了,但是我们还看不到他,因为系统并没有把窗口显示到我们的屏幕上。如果我们需要察看这个窗口,就需要调用API函数ShowWindow来显示我们的窗口及调用函数UpdateWindow来更新窗口。这两个函数的声明如下:
BOOL ShowWindow(
HWND hWnd, // 需要显示的窗口的句柄
int nCmdShow // 窗口的显示方式
);
BOOL UpdateWindow(
HWND hWnd //需要刷新的窗口的句柄
);
经过上述步骤之后,一个窗口就展现在我们面前了。但是,这个窗口目前还不能响应事件,因为我们还没有为他添上事件代码。在下一章中我们将讲述Win32API响应事件的消息机制。