这个概要讨论了窗口的特点,例如,窗口类型、状态、大小和位置。
窗口类型:
重叠窗口:
重叠窗口是一个顶层窗口,有标题栏、窗体和用户区域。用于程序的主窗口。也可以有菜单栏、最小化和最大化按钮和滚动栏。重叠窗口典型应用包含所有构件的主窗口。
通过在CreateWindowEx函数中指定WS_OVERLAPPED或WS_OVERLAPPEDWINDOW样式,程序就可以创建一个重叠窗口。如果你使用WS_OVERLAPPED样式,窗口只拥有一个标题栏和一个窗体。如果你使用WS_OVERLAPPEDWINDOW样式,窗口将拥有标题栏、窗体、菜单栏、最小化和最大化按钮。
弹出式窗口:
弹出式窗口是一种特定类型的重叠窗口,用于对话框、消息框和出现在主窗口之外的临时性窗口。标题栏对于弹出式窗口是可选的。除此以外,弹出式窗口和WS_OVERLAPPED样式的主窗口是相同的。
在CreateWindowEx函数中你可以通过指定WS_POPUP样式创建弹出式窗口。指定WS_CAPTION样式可以包含标题栏。使用WS_POPUPWINDOW样式可以创建包含有窗体和菜单栏的弹出式窗口。WS_CAPTION样式必须和WS_POPUPWINDOW样式联合使用才能得到拥有可见菜单的弹出式窗口。
子窗口:
子窗口有一个WS_CHILD样式并被限制在其父窗口的用户区域。典型的应用是用子窗口按功能区域划分其父窗口的用户区域。通过在CreateWindowEx函数中指定WS_CHILD样式创建子窗口。
一个子窗口必须有父窗口。父窗口可以是重叠窗口、弹出式窗口、甚至是其他子窗口。当你调用CreateWindowEx函数时你要指定一个父窗口。如果你在CreateWindowEx函数中指定了WS_CHILD样式但没有指定父窗口,系统就不能创建这个窗口。子窗口除了一个用户区域没有其他特征,除非他们有明确的要求。程序可以为子窗口申请标题栏、窗口菜单、最小化和最大化按钮、窗体和滚动条,但子窗口不能拥有菜单。在注册子窗口或创建子窗口时,即使程序指定了一个菜单句柄,菜单也将被忽略。如果没有指定窗体样式,系统将创建一个无窗体窗口。程序可以使用无窗体子窗口去划分父窗口的用户区域,这种划分对用户是不可见的。
定位:
系统总是把子窗口定位到父窗口用户区域的左上角。子窗口的任何部分都不能出现在父窗口窗体之外。如果程序创建了一个比父窗口更大的子窗口或者子窗口的位置超越了父窗口的窗体,系统将裁剪子窗口;也就是,父窗口用户区域之外的部分将不显示。如下所述,影响父窗口的动作也能影响子窗口。
父窗口 | 子窗口 |
Destroyed(销毁) | 在父窗口被销毁之前销毁 |
Hidden(隐藏) | 在父窗口隐藏之前隐藏,父窗口可见时子窗口才可见 |
Moved(移动) | 随父窗口的用户区域移动 |
Shown(显示) | 父窗口显示后显示 |
裁剪:
系统不能从父窗口的用户区域自动裁剪子窗口。这意味着如果父窗口在和子窗口相同的位置进行任何绘画,它将覆盖在子窗口之上。然而,如果父窗口有WS_CLIPCHILDREN样式,系统将根据父窗口用户区域裁剪子窗口。如果子窗口被裁剪了,那么父窗口就不能覆盖它。
在相同的用户区域子窗口可以覆盖其他的子窗口。和其他某个或多个子窗口共享同一个父窗口的子窗口被成为同胞窗口。同胞窗口可以在对方的用户区域绘画,除非它们中的一个拥有WS_CLIPSIBLINGS样式。如果有一个子窗口有这个样式,位于子窗口之内任何部分的同胞窗口将被裁剪。
如果一个窗口拥有WS_CLIPCHILDREN样式和WS_CLIPSIBLINGS样式中的一种,在性能上有轻微的损失。每个窗口都占用系统资源,因此程序不要任意使用子窗口。为了得到更好的性能,需要逻辑划分主窗口的程序可以通过主窗口的窗口程序实现而非通过使用子窗口。
关联到父窗口:
程序可以通过调用SetParent函数改变子窗口的父窗口。正因为如此,系统可以把子窗口从原有的父窗口移到新的父窗口中。如果SetParent函数指定了一个NULL句柄,桌面窗口将成为新的父窗口。正因为如此,子窗口可以画在桌面窗口中,处在其他窗口窗体之外。GetParent函数返回子窗口的父窗口句柄。
父窗口让出一部分用户区域给子窗口,并且子窗口从这个区域接受所有输入。窗口类不需要为父窗口中的每个子窗口设置成相同。这意味着程序能够满足一个父窗口可以拥有不同外观和进行不同任务的子窗口。例如,一个对话框可以包含许多类型的控件,对于用户来说每个子窗口可以接受不同类型的数据。
一个子窗口只有一个父窗口,但一个父窗口可以有许多子窗口。每个子窗口依次可以有自己的子窗口。在这个窗口链中,每个子窗口都可以被原始父窗口的后代窗口所调用。程序使用IsChild函数来判断给定的窗口是否是子窗口或给定父窗口的后代窗口。
EnumChildWindows函数列举了父窗口的所有子窗口。然后,EnumChildWindows函数把每个子窗口的句柄传递给程序定义的回调函数。给定父窗口的所有后代窗口也被列举出来。
消息:
系统直接把子窗口的输入消息传递给子窗口;这些消息不通过父窗口传递。如果通过EnableWindow函数禁用了子窗口,这种情况例外。在这种情况下,系统将传递给子窗口的所有输入消息改传递给其父窗口。如果需要,允许父窗口检查这些消息并使子窗口可用。
子窗口有一个独特的整型标识符,当和控件窗口一起运行时子窗口标识符是重要的。程序通过给它发送消息来控制控件的活动。程序通过使用子窗口标识符给控件窗口发送消息。另外,控件发送通知消息给它的父窗口。通知消息包含在控件子窗口标识符中,父窗口通过标识符判断哪个控件发送的消息。程序通过设置CreateWindowEx函数的hMenu参数值而不是菜单句柄来为其他类型的子窗口指定子窗口标识符。
层叠窗口:
使用层叠窗口可以明显提高性能和拥有复杂外型、动态外型或希望使用Alpha混合效果窗口的视觉效果。系统自动组合和重绘层叠窗口与下层程序窗口。结果,层叠窗口渲染流畅,复合窗口区域没有典型的闪烁。另外,层叠窗口能够部分半透明,那是,Alpha混合。
当调用CreateWindowEx函数时指定WS_EX_LAYERED扩展窗口样式就可以创建一个层叠窗口,或者在创建窗口后调用SetWindowLong函数来设置WS_EX_LAYERED。CreateWindowEx函数调用后,直到为这个窗口调用了SetLayeredWindowAttributes函数或UpdateLayeredWindow函数,层叠窗口才能显现。注意:WS_EX_LAYERED样式不能用于子窗口。
调用SetLayeredWindowAttributes函数为给定的层叠窗口设置不透明层或透明色键。当函数调用后,当显示窗口或改变窗口大小时系统可能仍然要求绘画窗口。不过,由于系统存储了层叠窗口的镜像。如果相关窗口在桌面移动的话,系统将不要求绘画窗口。如果想为一个窗口添加半透明或通明效果,原有程序不需要重新构建绘画代码,因为系统调用SetLayeredWindowAttributes函数重新绘画窗口。
为了得到更快和更有效率的动画或者如果每个像素都需要混合,调用UpdateLayeredWindow函数。当程序必须直接支持了层窗口的外型和内容时,首先使用UpdateLayeredWindow函数,而不使用SetLayeredWindowAttributes函数。另外,直接使用UpdateLayeredWindow函数可以更有效的使用内存,因为系统不需要为存储窗口镜像占用额外的内存。为了得到动画窗口的最大效率,调用UpdateLayeredWindow函数改变层叠窗口的位置和大小。请注意:调用SetLayeredWindowAttributes函数后,调用UpdateLayeredWindow函数将失败,直到清除并重新设置层叠窗口样式位。
点击测试基于外型和透明度的层叠窗口。这意味着被色键或其Alpha值为零的窗口区域将允许鼠标消息通过。然而,层叠窗口拥有WS_EX_TRANSPARENT扩展窗口样式,层叠窗口的外型将被忽略,并且鼠标事件将被传递给下层的层叠窗口。
消息窗口:
消息窗口允许你发送和接收消息。它不可见、没有Z顺序、不能被列举、并且不能接收广播消息。这种窗口只是简单地传递消息。为CreateWindowEX函数的hWndParent参数指定HWND_MESSAGE常量或一个已存在的消息窗口句柄,就能创建一个消息窗口。你也可以通过为SetParent函数的hWndNewParent参数指定HWND_MESSAGE,就可以把一个已存在的窗口改变成消息窗口。为FindWindowEx函数的hWndParent参数指定HWND_MESSAGE,就能找到消息窗口。另外,如果hWndParent参数和hWndChildAfter参数都为空,那么FindWindowEx函数搜索消息窗口和顶层窗口一样。
窗口关系:
前景和背景窗口:
每个进程可以有多个线程,每个线程都能够创建窗口。创建正和用户一起工作窗口的线程能被前景线程所调用,并且这个窗口可以被前景窗口调用。所有其他线程使背景线程,背景线程创建的窗口能够被背景窗口所调用。每个线程都有一个优先级别,这个优先级别决定了这个线程获得cup时间。尽管程序可以设置线程的优先级别,一般情况下,前景线程的优先级别略高于背景线程的优先级别。由于这个原因,前景线程获得cpu时间比背景线程要多。前景线程的正常优先级别一般为9,背景线程的正常优先级别一般为7。
用户通过点击一个窗口或ALT+TAB或ALT+ESC组合键来设置前景窗口。使用GetForegroundWindow函数来获得前景窗口的句柄。通过GetForegroundWindow函数获得的句柄和你程序窗口的句柄相比较来检查你程序窗口是否使前景窗口。
程序通过使用SetForegroundWindow函数设置前景窗口。
Windows NT4.0或更早的版本、Windows 95:如果一个新的前景窗口是一个顶层窗口,系统将激活它;否则,将激活相关的顶层窗口。
Windows 98/me/2000/xp:系统限制了哪个系统可以设置前景窗口。只有满足下面条件中的一个,进程才可以设置情景窗口:
Windows2000/xp:能够设置前景窗口的进程通过调用AllowSetForegroundWindow函数或通过调用带有BSF_ALLOWSFW标记的BroadcastSystemMessage函数来使的其他进程能够设置前景窗口。前景进程可以通过LockSetForegroundWindow函数使的SetForegroundWindow函数调用失效。
私有窗口:
一个重叠窗口或弹出式窗口可以被其他重叠窗口或弹出式窗口所私有。成为共有窗口有几个限制:
在z顺序上,私有窗口总是在拥有这些窗口的主窗口之下
当其主窗口销毁时,系统自动销毁私有窗口
当其主窗口最小化时,私有窗口将被隐藏
只有重叠窗口或弹出式窗口可以成为私有窗口;子窗口不能成为私有窗口。当创建带有WS_OVERLAPPED样式或WS_POPUP样式的窗口时,程序可以通过指定主窗口句柄作为CreateWindowEx函数的hWndParent参数来创建私有窗口。hWndParent参数必须标识成重叠窗口或弹出式窗口的句柄。如果hWndParent参数标识成子窗口句柄,系统将所有权分配给子窗口的顶层父窗口。创建了私有窗口后,程序不能把这个窗口的所有权转给其他窗口。
默认情况下,对话框和消息框都是私有窗口。当调用函数创建一个对话框或消息框时,程序要指定其主窗口。
程序可以使用带有GW_OWNER标记的GetWindow函数获得主窗口的句柄。
z顺序:
一个窗口的z顺序指出了其在重叠窗口堆中的位置。这个窗口堆是朝着一个虚构的轴向,z轴向,从屏幕向外延伸。
在Z顺序最上面的窗口覆盖其他所有的窗口。在Z顺序最下面的窗口被其他所有窗口所覆盖。
系统维护一个Z顺序列表。系统添加窗口到Z顺序表中,不论它们是最高层窗口、顶层窗口还是子窗口。最高层窗口覆盖其他非最高层窗口,不论它是激活窗口或前景窗口。最高层窗口拥有WS_TOPMOST样式。在Z顺序中所有最高层窗口出现在其他非最高层窗口之前。在Z顺序中,子窗口是和其父窗口组合在一起的。
当一个程序创建一个窗口时,系统将它放在相同类型窗口z顺序中的最顶端。你也可以使用BringWindowToTop函数把一个窗口放到相同类型窗口Z顺序中的最顶端。你也可以使用SetWindowPos函数或DeferWindowPos函数重新排列Z顺序。
用户通过激活不同窗口改变Z顺序。系统把激活窗口放在相同类型窗口Z顺序的最顶端。当一个窗口来到Z顺序的最顶端,其子窗口也来到Z顺序的最顶端。你可以使用GetTopWindow函数搜索一个父窗口的所有子窗口,并把句柄返回给Z顺序最顶端的子窗口。GetNextWindow把句柄返回给Z顺序中下一个或前一个窗口。
窗口显示状态:
激活窗口:
激活窗口是用户使用程序的最顶层的窗口。为了用户更容易识别激活窗口,系统把它放置在Z顺序的顶端并把标题栏和窗体的颜色改变为系统默认的激活窗口的颜色。只有顶层窗口可以成为激活窗口。当用户在子窗口上操作时,系统会激活拥有这个子窗口的顶层父窗口。
在某一时刻,系统只有一个顶层窗口。用户通过点击窗口或其子窗口来激活它,或通过使用ALT+TAB、ALT+ESC组合键。一个程序通过使用SetActiveWindow函数来激活顶层窗口。其他函数可以导致系统激活一个不同的顶层窗口,包括SetWindowPos、DeferWindowPos、SetWindowPlacement和DestroyWindow函数。尽管一个程序在任何时候可以激活一个不同的顶层窗口,为了避免用户困惑,只有响应用户激活时才如此。程序通过使用GetActiveWindow函数来获得激活窗口的句柄。
当改变一个程序的顶层窗口为另一个程序的顶层窗口时,系统会发送WM_ACTIVATEAPP消息给两个程序,通知它们这种改变。当在同一的程序中激活不同窗口时,系统将发送一个WM_ACTIVATE消息给两个窗口。
禁用窗口:
一个窗口可以被禁用。一个被禁用的窗口将不接收用户的键盘或鼠标输入,但它能接收其他窗口、其他程序或系统的消息。一个程序可以禁用一个窗口来防止用户使用这个窗口。例如,程序可能禁用一个对话框上的按钮来防止用户关闭它。程序可以在任何时候使禁用窗口变为可用;能够恢复正常输入。默认情况下,刚创建的窗口是可用的。程序可以使用WS_DISABLE样式来禁用一个新的窗口。一个程序可以通过使用EnableWindow函数来使可用或禁用一个已存在的窗口。在窗口变得可用之前,系统会给它发送一个WM_ENABLE消息。程序可以使用IsEnableWindow函数来判断窗口是否是可用窗口。
当子窗口被禁用时,系统会把给子窗口得鼠标输入传递给其父窗口。父窗口用这个消息来判断是否要使子窗口可用。更多信息,参考Mouse Input。
某一时刻只有一个窗口可以获得键盘输入,那么认为此窗口有键盘焦点。如果程序通过EnableWindow函数禁用了有键盘焦点的窗口,那么此窗口除了被禁用以外还失去了键盘焦点。EnableWindow函数会设置键盘焦点为NULL,意思是没有窗口有焦点。如果一个子窗口或其他后代窗口有键盘焦点,当父窗口被禁用时其后代窗口也会失去焦点。更多信息,参考Keyboard Input。
窗口可见性:
一个窗口既可以可见也可以隐藏。系统在屏幕上显示可见窗口。它通过不画窗口来隐藏要隐藏的窗口。如果一个窗口是可见的,那么用户就能够为这个窗口提供输入并浏览这个窗口的输出。如果一个窗口被隐藏,那么它也就不可用。一个隐藏的窗口可以处理系统或其他窗口发送给它的消息,但不能处理用户的输入或显示输出。程序在创建一个窗口时就设置了它的可见状态。然后程序可以改变它的可见状态。
当一个窗口设置了WS_VISIABLE样式它是可见的。默认情况下,CreateWindowEx函数创建一个隐藏的窗口,除非程序指定了WS_VISIABLE样式。程序在创建窗口之后设置WS_VISIABLE样式,创建过程的细节对用户是隐藏的。例如,程序可能会保持窗口的隐藏直到它定制窗口显现。如果在CreateWindowEx函数中指定了WM_VISIABLE样式,那么系统在创建这个窗口之后,在显现它之前,会给这个窗口发送一个WM_SHOWWINDOW消息。
程序可以通过IsWindowVisiable函数来决定窗口是否可见。程序可以通过ShowWindow、SetWindowPos、DeferWindowPos、SetWindowPlacement、SetWindowLong函数来显示或隐藏窗口。这些函数通过设置和清除WS_VISIABLE样式来显示或隐藏窗口。在显示或隐藏之前也要发送WM_SHOWWINDOW消息给此窗口。
当私有窗口被最小化时,系统自动隐藏此窗口。相同地,当私有窗口被恢复时,系统自动显示此窗口。在这两种情况下,系统在显示或隐藏窗口之前给它发送WM_SHOWWINDOW消息。偶尔地,程序可能会没有最小化窗口地情况下需要隐藏私有窗口或其主窗口。在这种情况下,程序使用ShowOwnedPopup函数。这个函数会为所有私有窗口设置或清除WS_VISIABLE样式并在显示或隐藏这些私有窗口之前给他们发送WM_SHOWWINDOW消息。隐藏主窗口不影响私有窗口地可见状态。
当一个父窗口可见时,和它相关地子窗口也可见。同样地,当父窗口被隐藏,其子窗口也被隐藏。最小化父窗口不影响其子窗口地可见状态。也就是,子窗口和父窗口一起最小化,但不改变WS_VISIABLE样式。
即使窗口拥有WS_VISIABLE样式,用户也可能在屏幕上看不到这个窗口;可能其他窗口完全覆盖了它或它被移到了屏幕之外了。并且,一个可见子窗口会受到通过父子关系确立地裁剪规则的限制。如果此窗口的父窗口不可见,那么它也不可见。如果父窗口被移到了屏幕之外,那么子窗口也被移到屏幕之外。
最小化、最大化和恢复窗口:
最大化窗口是一个含有WS_MAXIMIZE样式的窗口。默认情况下,系统描述最大化窗口是它能填充整个屏幕,或着对于子窗口就是父窗口的用户区域。尽管一个窗口的大小能够设置成和最大化窗口相同的大小,但它们之间有稍微的不同。系统自动将标题栏移到屏幕的顶端或者父窗口用户区域的顶端。系统也可以禁用标题栏和改变窗体大小的功能,使窗口不能移动和改变大小。
最小化窗口是一个含有WS_MINIMIZE样式的窗口。默认情况下,系统把最小化窗口缩小到一个任务栏的大小并把最小化窗口移动到任务栏。恢复窗口是把这个窗口恢复到上一次的位置和大小,也就是,被最大化或最小化之前的大小。
如果一个程序在CreateWindowEx函数种使用了WS_MAXIMIZE或WS_MINIMIZE样式,窗口将被初始化成最大化或最小化。创建一个窗口后,程序可以使用CloseWindow函数来最小化这个窗口。ArrangeIconicWindows函数在桌面排列最小化窗口图标或者是父窗口中的子窗口最小化图标。OpenIcon函数恢复最小化窗口之前的位置和大小。
ShowWindow函数能够最小化、最大化、恢复一个窗口。也能设置窗口的可见和激活状态。SetWindowPlacement函数和ShowWindow函数功能基本相同。但它不能改变最大化、最小化和恢复的位置。
IsZoomed和IsIconic函数判断给定的函数是最大化还是最小化。GetWindowPlacement函数返回最小化、最大化、恢复窗口的位置并确定了窗口的显示状态。当系统接收到最大化或恢复最小化的窗口命令时,它给这个窗口发送一个WM_QUERYOPEN的消息。如果窗口程序返回了一个FALSE,系统忽略最大化或恢复命令。
系统会自动为最大化窗口设置系统默认的最大化窗口的位置和大小。当系统最大化此窗口时,程序也可以调用SetWindowPlacement函数或处理这个窗口接收到的WM_GETMAXMININFO消息。WM_GETMAXMININFO包含了一个含有系统设置的最大化窗口大小和位置的值的结构指针。用这些值替换默认值。
窗口大小和位置:
默认大小和位置: