1、4永远的窗口如果windows一直存在下去,窗口这个话题也许是永恒的1. 一切皆窗口在我看来桌面上的一切都是窗口,桌面本身是窗口,开始菜单是窗口,桌面上永远置顶的播放器是个置顶的窗口,工具栏是个子窗口.不仅我这么看,Spy+也这么看,如下图:图 11 Spy+和桌面一切都是窗口,窗口错落有致,成为界面树上的翩翩叶子,组织成了我们所看到的整个Windows系统用户界面。我们首先通过一个普普通通典型的窗口,来分析一下窗口的组成: 图 12 普普通通的窗口 一个窗口是有很多界面元素的,比如标题栏,菜单栏,状态栏等等。但实际上可以把这些归为两类,一类是客户区,客户区就是整个窗口中间的部分,在图中已经标
2、示出来。客户区是由程序员负责绘制的,程序员可以在上面写个字或者画个圆这样。而另一类当然是非客户区,除了图上客户区以外的地方,标题栏,水平滚动条等等都是非客户区,这一部分的绘制是由操作系统负责的。 界面元素是看的见的,还有一些窗口特性我们用上图是无法表示出来的,比如窗口该如何响应用户的输入?比如窗口的鼠标应该是什么样的,是单箭头或者是其他比较炫的鼠标效果?比如客户区的背景色应该是什么样的等等。归纳起来就是两点:(1) 窗口的界面元素分成两类,一类是客户区,另一类是非客户区;(2) 窗口的特性,看得见的,看不见的,七大姑八大姨的,确实很多。一个成功的窗口需要程序员和操作系统默契配合。操作系统作一些
3、通用的,基础的工作,比如绘制一个标题栏,状态栏这样的事情。程序员作一些特定的工作,比如读一个数据文件,然后用图形化的方式显示在窗口客户区内。2. 窗口的创建前面我说了,窗口的特性是很多的。不是一般的多,而是七大姑八大姨般的多。因此窗口的创建,一般的方法,那就麻烦了。程序员需要一个一个指定这些特性,看得见得要指定,看不见的还要指定。不仅如此,每打算创建一个窗口,你就要指定一次,无论这些窗口有多么类似,你还是要不厌其烦地指定下去。有些人怕麻烦,他指定了三五个特性,最终宣布“这真不是人干的活,老子金盆洗手了”,这些人,我们只有哎有些人不怕麻烦,他会老老实实一遍一遍指定下去,这些人,我们尊敬他们. 还
4、有些人怕麻烦,于是他们想出了新的办法,这些人,我们只有崇拜.技术精英们想出的办法是“把共性的东西,抽象出来”。这句话我在下面会慢慢解释。2.1 把共性的东西,抽象出来在Windows操作系统里,我们是用窗口句柄(HWND)来操作一个窗口的。HWND就相当于每个窗口的钥匙。Windows里CreateWindow或者CreateWindowEx都是创建一个窗口的函数,它们返回 HWND类型的一个值,以便程序员继续对窗口进行操作。这个值对应的是桌面上一个一个实实在在的窗口,我们看到这些窗口有很多特性是类似的,比如窗口客户区的背景色都是白色的,鼠标的光标形状都是一样的等等。于是技术精英们就把这些共性
5、的东西抽象出来了,抽象成了一个结构,这个结构我们称之为窗口类(windows class)。typedef struct UINTstyle; WNDPROClpfnWndProc; intcbClsExtra; intcbWndExtra; HINSTANCEhInstance; HICONhIcon; HCURSORhCursor; HBRUSHhbrBackground; LPCTSTRlpszMenuName; LPCTSTRlpszClassName; WNDCLASS, *PWNDCLASS;代码 21 窗口类结构体 这里面最为重要的是第二个成员窗口过程,如果把窗口比作有生命的物体
6、,那么窗口过程就注入了灵魂。这个我们需要在消息循环一节当中解释。其他的比较常用的成员变量,比如hIcon指定了应用程序的图标,hCursor指定了鼠标的形状,hbrBackground指定了客户区的背景色,lpszMenuName指定了窗口类的菜单,lpszClassName指定了窗口类的名字等等。这些特性是每个窗口都具备的共性,因此全部抽象成了窗口类的成员变量。窗口类和窗口的关系,在面向对象里我们可以把它们比作类和对象的关系。但是更贴切的比喻,我认为是模具和成品的关系。窗口类好比一个个模具,想要做按钮,我们就拿一个按钮的模具,倒成一个模子,然后再在上面做一些慢工细活,成为一个按钮。想做组合框
7、,我们就拿一个组合框的模具,想做编辑框,我们就拿一个编辑框的模具,想做一个花瓶,我们就拿. 问题来了,操作系统没有提供花瓶的模具,不过也有办法,操作系统会告诉我们,你把模具的特性告诉我,我会给你制作一个花瓶的模具。 有Win32经验的程序员都知道,每次创建窗口之前,我们都会调用一个函数RegisterClass,注册窗口类。注册窗口类实际上就是告诉操作系统模具的特性和要求,让操作系统为我们制作一个模具。因此一个标准的窗口创建过程,如下所示:LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam
8、);int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) static TCHAR szAppName = TEXT(HelloWin); HWND hwnd; WNDCLASS wndclass; / 注册窗口 wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0
9、; wndclass.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION); wndclass.hCursor = LoadCursor(NULL,IDC_ARROW); wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = szAppName; if(!RegisterClass(&wndclass) return 0; / 创
10、建窗口并显示窗口 hwnd = CreateWindow(szAppName,TEXT(The Hello Program), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL,NULL,hInstance,NULL); ShowWindow(hwnd,nCmdShow); UpdateWindow(hwnd); / . return 0;LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPA
11、RAM lParam) return DefWindowProc(hwnd,message,wParam,lParam);代码 22 标准的窗口创建过程但是这个还远没有结束。按照毛主席老人家的话,这是“万里长征第一步”。如果运行一下这个程序,窗口犹如昙花一现,一闪而过。这其中的原因,我们还是要留在后面介绍。操作系统之所以能够找到指定的模具来制作窗口,主要是靠窗口类的类名(lpszClassName)。我们可以看到CreateWindow的第一个参数便是窗口类的类名,操作系统根据这个类名去寻找相应的系统窗口类或者是应用程序注册的窗口类。2.2 唏嘘感慨几句说到这里,真的是要唏嘘感慨几句。相信绝大
12、多数程序员都有这个认识,就是C语言是过程语言,而C+是面向对象的语言。但是Win32掷地有声地告诉我们,语言只是载体,用C语言同样可以写出面向对象思想的程序。窗口类和窗口即是明证。此外,如果你是从Win32,MFC, WinForm到现在最为流行的WPF一路走来,同样也会感到微软的技术进步带给程序员的便利。我自认为对Win32还算是熟悉,但是让我创建一个窗口的时候,我往往也是要从MSDN里找出一段代码Copy上去,或者是直接利用向导创建一个HelloWorld。在MFC里,事情并没有得到好转,虽然我们可以利用向导直接得到一个单文档,多文档或者是基于对话框的应用程序,但是我们连应用程序的入口(W
13、inMain)都找不到了。相信每个MFC程序员,在早期的MFC学习当中都是痛苦不堪的。在WinForm中创建窗口,真正的变的简单。多简单?一句话。只需要一句话,一个窗口就创建出来了。static void Main() Application.Run(new HelloWorldWinForm();代码 23 WinForm里创建窗口按理说,WinForm已经简单到了极致。WPF没有理由再简单,但他还是做到了。因为在WPF里甚至不需要写任何程序,只需要在指定应用程序启动的时候启动那个窗口文件即可。代码 24 WPF里创建窗口所以真的是不从历史这样一步一步走到当代,就看不出进步。这几个例子的源码我都写好了,放在附件文件夹下,各位的机器有VC6.0和VS2008的环境的话即可运行。3. 窗口的类型注册完窗口类,紧接着就是创建窗口,过去在创建窗口的时候,我很拿不准的就是指定样式(CreateWindow的第三个参数)。因为窗口的样式确实太多,我简单统计了一下窗口样式有18种,也许有人觉得不算多,但是这18种还是可以任意组合的。这样就真是无穷无尽了。但是好好的归纳和总结,事情是可以变的简单的。真正的窗口类型只有5种,而真正常用的只有3种。下面,我需要分别介绍一下这5种窗口类型,实际上搞清楚前3种,大体也就OK
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1