VC中设置程序窗口的排列层级

1. topmost窗口和non-topmost窗口

        Windows中的应用程序窗口,可以按照显示效果分为topmostnon-topmost两类。top-most类型的窗口,显示时位于non-topmost类型窗口的上方。当topmost类型窗口不是活动窗口时,它失去了输入焦点,但是依然会位于non-topmost类型窗口之上。

        下面举一个例子,假定某个应用程序A的窗口是topmost类型,启动该程序,再启动Windows自带的记事本Notepad.exe程序。Notepad.exe程序的窗口类型是non-topmost,此时屏幕上的显示类似于下图:


        由于先启动应用程序A,再启动记事本。所以当前活动窗口是记事本,输入焦点也在记事本中。如果我们敲击键盘,将在记事本中输入文字。应用程序A的窗口类型是topmost,所以它还是覆盖在记事本之上,有可能遮挡住一部分记事本窗口的内容。

        上图显示的情景是存在一个topmost窗口和一个non-topmost窗口。可能同时存在多个topmost类型的窗口、以及多个non-topmost类型窗口,那么同一个类型的窗口会按照某种顺序上下排列起来。对于不同类型的窗口来说,在topmost窗口集合中的任何一个窗口,都将位于所有non-topmost窗口之上。


2. Z-OrderZ坐标轴顺序)

   我们可以将计算机屏幕看作一个二维平面,那么可以假想它有水平坐标轴X和垂直坐标轴Y,如下图所示:

    当计算机屏幕上有多个窗口时,我们可以将屏幕想象成一个拓展的三维空间,即增加一个坐标轴Z,如下图所示:

        MSDN上于WindowFeatures的介绍中提到了Z-order(链接为:https://msdn.microsoft.com/en-us/library/windows/desktop/ms632599(v=vs.85).aspx#zorder),说法大致如下:Windows操作系统用Z-order来指示窗口栈中的某一个窗口的前后位置。可以想象存在一个Z坐标轴,该坐标轴从计算机屏幕由里向外(即朝观察者方向)伸展,Z-order最顶端的窗口处于最上层,离观察者最近,将覆盖下层的其他窗口。Z-order最底端的窗口处于最下层,被所有之上的窗口层层覆盖,操作系统将屏幕上所有窗口的Z-order保存在一个列表中。topmost类型的窗口集中的任何一个窗口,都处于non-topmost窗口集中所有窗口的层次之上。这种排列方式与窗口是否处于活动状态无关,当活动窗口是一个non-topmost窗口时,如果存在topmost类型的窗口,所有topmost类型的窗口还是会覆盖在当前活动窗口之上,读者可以回想一下前面举的应用程序A与记事本程序窗口前后排列的例子。

        当应用程序新建了一个窗口时,操作系统将根据窗口的类型,将它放置到同类型窗口的最上方,即同类型窗口Z-order的最顶层。当用户激活某一个窗口时(比如用鼠标点击该窗口的标题栏操作),该窗口的Z-order也会被改变,操作系统会将该窗口的Z-order提升到同类型窗口的最顶层。比如该窗口是一个non-topmost类型窗口,用户激活它之后,它将位于non-topmost类型窗口集的最上层,但仍然位于所有tompost窗口之下。当一个程序窗口被操作系统调整到Z-order的最顶层时,它的子窗口也会被放到最顶层。


3.VC中设置窗口排列层级的函数

        VC中可以改变窗口排列层级的函数很多,最主要的一个函数是SetWindowPos()。该函数定义如下:

BOOL WINAPI SetWindowPos(

 _In_    HWND hWnd,

 _In_opt_ HWND hWndInsertAfter,

 _In_    int X,

 _In_    int Y,

 _In_    int cx,

 _In_    int cy,

 _In_    UINT uFlags

);

    第1个参数HWND hWnd代表窗口的句柄,第2个参数hWndInsertAfter用来指定窗口将被调整到上下层中的哪一个层次中去,它有以下四种宏定义的取值:

        HWND_BOTTOM——将该窗口放到Z-order排列顺序的最底层。如果这个窗口是一个topmost窗口,使用HWND_BOTTOM参数调用SetWindowPos()函数之后,这个窗口将不再是topmost类型,并被放到所有其他窗口之下,即如果此时还存在non-topmost类型的其他窗口,哪怕当前窗口是一个topmost类型窗口,它也将被放到其他non-topmost类型窗口之下,也就是变为所有窗口中最底层的那一个。

        HWND_NOTOPMOST——将该窗口放到所有non-topmost窗口之上、所有topmost窗口之下。即该窗口将被放到non-topmost类型窗口集与topmost窗口集之间的位置。

        HWND_TOP——将该窗口放到同类型窗口中Z-order顶层的位置。注意仅仅是同类型窗口集的最上层。

        HWND_TOPMOST——将该窗口放到所有non-topmost窗口之上,即将该窗口变成一个topmost类型的窗口,而且该窗口在topmost窗口集中也处于最顶层,也就是说,将该窗口的位置放到屏幕Z坐标轴方向的最上层。这时如果再启动一个non-topmost类型的窗口(比如记事本程序),该窗口就不再是活动窗口,但它依然位于non-topmost窗口之上。读者可以回想一下前面举的应用程序A与记事本程序窗口前后排列的例子。

        SetWindowPos()的第2个参数取值为HWND_TOP时,调用该函数与BringWindowToTop()类似,都只能将窗口放到同类型窗口集中的最顶层。我们不能望文生义,以为HWND_TOPBringWindowToTop的意思就将窗口放到屏幕最前端。因为如果此时窗口类型是non-topmost,而且存在topmost类型的窗口,调用BringWindowToTop()或将SetWindowPos()的第2个参数设为HWND_TOP,其效果只是将该窗口放到了non-topmost窗口集的最上层,但在该窗口之上还覆盖着topmost窗口集。

        如果我们希望将应用程序的窗口放到屏幕最前端,在其他所有窗口之上显示,可以调用SetWindowPos()函数并将其第2个参数取值为HWND_TOPMOST,或者调用SetForegroundWindow()函数。SetForegroundWindow()函数有很多使用限制,详细信息可以查阅MSDN

        SetWindowPos()的第2个参数取值为HWND_TOPMOST时,调用该函数会将窗口放置于屏幕的最上层。但是并不能保证该窗口会一直保持在最上层。因为其他程序也可能会修改Z-order,比如再启动另一个程序,那个程序也用同样的方法(调用SetWindowPos()并把第2个参数取值为HWND_TOPMOST)设置窗口,那么新启动的程序窗口将出现在最上层,即topmost窗口集的最外层,而原来的程序窗口的层次会下调一级,即位于topmost窗口集的次外层。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值