什么遮盖该窗口,看了多少个钟头照旧弄不出来

图片 1

大一新生假期实习。。

怎样在创建一个子窗口窗口后禁用原窗口,关闭子窗口后原窗口又可用..
如题… 😥 我是个新手才接触GUI编程 ….求教…

hwndParent 
[in] Handle to the parent window whose child windows are to be
searched. 
If hwndParent is NULL, the function uses the desktop window as the
parent window. The function searches among windows that are child
windows of the desktop.

winform一个窗口隐藏,另一个窗口打开
登陆之后,如何隐藏该窗口,打开另一个窗口图片 1

caseWM_LBUTTONDOWN:{pt.x=LOWORD(lParam);pt.y=HIWORD(lParam);}
  1. #define WS_OVERLAPPED       0x00000000L
  2. #define WS_POPUP            0x80000000L
  3. #define WS_CHILD            0x40000000L

可是LOWORD下面一直有波浪线啊。。。说未定义标识符lParam。。。求救。。看了几个小时还是弄不出来

算是“成功穿越”了,这时候你再给父窗口加上WS_CLIPCHILDREN看看,结果我就不说了,就算不尝试其实也能想得到。相信大家到此为止都理解了这两个风格的作用了。

只制定了一个WS_OVERLAPPEDWINDOW,但我们很快就找到了WS_OVERLAPPEDWINDOW的定义:

图片 2

我们现在来进行一些稍微复杂点点的实验,就是创建A弹出窗口,其Owner为主窗口,创建B弹出窗口,其Owner为A窗口,创建C弹出窗口,其Owner为B窗口。步骤模仿上面的窗口创建步骤即可,好,编译,运行,效果大致如此:

现在把这个语句改为:

用VC++的向导创建一个Hello
World的Windows程序,注意是Windows程序,不是MFC的Hello
World,这样我们可以绕开MFC,专注于查看一些Windows的技术细节,编译,运行。

图片 3

上图表示了App Window及其子窗口的关系,现在假设我们要销毁Parent Window
1(对应的对象指针是m_pWndParent1),我们可以m_pWndParent1->DestroyWindow(),这样Child
Window 1,Parent Window 2,Child Window
2都被销毁了,销毁的时候这些窗口的OnDestry和OnNcDestroy都被调用了,最后delete
m_pWndParent1,此时m_pWndParent1->m_hWnd已经是NULL,不会再去调用Destroy,在析构的时候也就不会出现Warning。但如果不先执行m_pWndParent1->DestroyWindow()而直接delete
m_pWndParent1,那么在CWnd::~CWnd中就会调用DestroyWindow(m_hWnd),这样会产生WM_DESTROY和WM_NCDESTROY,会尝试去调用OnDestry和OnNcDestroy,但由于是在CWnd的函数~CWnd()的内部调用这两个成员,此时的虚函数表指针并不指向派生类的虚函数表,因此调用的其实是CWnd::OnDestroy和CWnd::OnNcDestroy,派生类的OnDestry和OnNcDestroy不被调用,但我们很多时候把释放内存等操作写在派生类的OnDestroy和OnNcDestroy中,这样,就容易导致内存泄露和逻辑混乱了。

Your window style (0x94c00880) has the high-order bit set and the next
bit clear so it is a popup window, not an overlapped window.

一眼看没什么奇怪的,但尝试拖动里边的窗口就出现些问题了,首先是显示在最前端的C窗口不能拖动(其实是被挡住了),然后你发现B也不能拖动,A可以,A一拖,就出现这种情况:

图片 4

运行结果如图:

图片 5

Look at these definitions from WinUser.h.

找到是不难,但如果光看这个就明白的话我也不必要写这种文章了,没有适当的代码去实践,估计很多人是不懂这两个风格什么含义的。OK,现在我来带你实践。spy++开着不?哈,别关啊,后面还要用到。用spy++观察各个top-level
window(非Child窗口)的属性,是不是都有个WS_CLIPSIBLINGS?想找个没有的都不行,如果你不服气,你要自己创建一个没有WS_CLIPSIBLINGS风格的顶层窗口,好吧,我在这里等你一会儿(……一会儿过去了……),你垂头丧气地回来了:“不行,即便我不指定这个风格,Windows也强制帮我加上。”那……你可以强制剥离掉这个风格啊,这样:

现在分析下一个风格WS_CLIPCHILDREN,前一个是裁兄弟姐妹,这个是裁孩子,微软也够狠的。不多说了,直接改代码来体会这个风格的作用,按照这个意思,有这个风格的父窗口在绘制的时候,不会把东西绘到子窗口的区域上去,这个嘛,简单,我们只要在父窗口的WM_PAINT里画点东西试试看就好了。代码还是前面的代码,把A,B,C都加上WS_CLIPSIBLINGS,主窗口不要WS_CLIPCHILDREN风格,我们看看是不是能把东西画到子窗口的区域去。

一、神秘的WS_OVERLAPPED

前面说了,子窗口不能显示在父窗口客户区之外,我们最常见的子窗口就是那些摆在对话框上的控件,什么button啊,listbox啊,combobox啊……都有个共同特点,不能拖动的,除非你重写它们的window
procedure,然后响应WM_MOUSEMOVE等消息,实现所谓“拖动”。那么有没有能够像应用程序主窗口那样有标题栏,能够被自由拖动的子窗口呢?——当然有!要创建是吗?简单,直接用MFC向导创建一个MDI程序即可,MDI的那些View其实就是可以自由拖动的子窗口,可以用spy++查看一下它们的属性,当然,你是不能把它们拖出主窗口的客户区的。也许你跟我一样,觉得MFC封装了过多的技术细节,想完全自己手动创建一个能拖动的子窗口,而且看起来就像个MDI的界面,OK,follow
me。

好吧,我们现在开始,一点点地通过实验去攻破这些难题!

图14

图12

图片 6

那我们如何来知道整个Z order的链表?可以这样:

执行后用spy++一看,还是没有把WS_CLIPSIBLINGS风格去掉,看来Windows是吃定你的了。嗯,前面说的都是top-level
window,那对于child
window呢?创建一个MFC对话框,在上面加几个button,然后增加/删除这几个button的WS_CLIPSIBLINGS风格?你除了发现child
window对与WS_CLIPSIBLING风格不再是强制的之外,恐怕仍然一无所获吧。还是得Follow
me,我还是不用MFC,用最简单的Windows
API。模仿第二节的创建几个popup窗口A、B、C的那个例子,只不过现在的CreateWindowEx改成这样:

这是内容最多的一节,做好心理准备。

OK,我们现在开始来尝试,看看这些风格究竟影响窗口几何,对了,准备spy++,这是必备工具。

那么我们很容易得到这个结论:style的最高位是1的,是一个popup窗口,style的次高位是1的,代表是一个child窗口,如果最高位次高位都是0,那这个窗口就是一个overlapped窗口,如果两位都是1,厄……MSDN告诉我们不能这么干,事实呢?我后面再讲。其实这个结论是有点过时的,甚至很能误导人,不是我们的原因,很可能是Windows的历史原因,为什么?具体也是后面讲。嘿嘿。

图18

图片 7

好,我不可能把所有的规则都列出来,但我相信前面所写的这些东西,对大家起到了抛砖引玉的作用了,其它规则,也可以通过类似的实验得出,或者用已有的规则去推导。那在转入下一节前,我提点问题:

微软和我们开了个玩笑,告诉我们,窗口和人一样,可以有父母,有主人……我们先来看一个最著名的Windows
API:

图片 8

那我们如何获取一个窗口的Parent和Owner?大家都知道API函数,GetParent,这是用来获取Parent窗口句柄的API——慢!这并不完全正确!大家再仔细点看看MSDN,再仔细点:

是不是很少遇到这种窗口组织结构?确实很少人这样用,而且哦,你会发现子窗口的标题栏没办法变为彩色,它一直是灰的,就表示它一直处于未激活状态,你怎么点它,拖它,调它,都没用的,而这个时候程序主窗口一直显示为激活状态,如何激活这个子窗口?我曾经对此苦思冥想,最后才知道,子窗口是无法被激活的,你立即反驳:“那MFC如何做到的?”哈哈,好,你反应够快,我下文会给你演示如何“激活”子窗口。(注意是加引号的)现在尝试移动主窗口,你会发现所有它的子窗口都会跟着主窗口移动的,这就好像我们看苹果落地一样,不会觉得奇怪,但你有没有想过,主窗口移动的时候,其子窗口对屏幕的位置也发生了变化,不变的是相对主窗口的客户区坐标。这就是子窗口的特性。再试试看启用/禁用主窗口,显示/隐藏主窗口看看,就不难得出结论:

  1. {
  2.  DWORD rtn;
  3.  HWND hw = GetParent(hWnd); //获取主窗口的“Parent”
  4.  if(hw==NULL)
  5.   rtn = GetLastError();
  6.  hw = GetParent(g_hwndA); //获取A的“Parent”
  7.  if(hw==NULL)
  8.   rtn = GetLastError();
  9.  hw = GetParent(g_hwndB); //获取B的“Parent”
  10.  if(hw==NULL)
  11.   rtn = GetLastError();
  12.  hw = GetParent(g_hwndC); //获取C的“Parent”
  13.  if(hw==NULL)
  14.   rtn = GetLastError();
  15. }

也许你还发现,点击子窗口的客户区不能让子窗口调整到其它子窗口的前面,窗口那个前,那个后的这种次序叫“Z
order”,又译作“Z轴”,order是“序”的意思,这其实是窗口管理器维护的一个链表,没错,是链表,不是数组,不是队列,不是堆栈,为什么是链表?因为窗口的次序经常发生变化,链表是最方便修改次序的了,只需要改变节点的指针,这点性能考虑,微软是肯定做过的。下面是窗口的Z
order的描述(我的描述,从MSDN改编):

  1. case WM_CREATE:
  2.  //…
  3.  SetTimer(hWnd, 1, 200, NULL);
  4.  break;
  5. case WM_TIMER:
  6.  if (wParam==1)
  7.   InvalidateRect(hWnd, NULL, TRUE);
  8.  break;

图5

虽然这么说,我还是认为,spy++给了我们不少误导,那么对WS_OVERLAPPED的讨论就暂时告一段落吧,作为一个技术人,很难容忍自己无法理解的逻辑,我就是这么种人……不过如果再扯下去的话这篇文章就不能结束了,所以姑且认为,这是spy++的错,而我们还是认为窗口分3种——popup,child和Overlapped。(Undocumented不在此列,也不在本文讲述之列)

规则十一:Owner隐藏,不会影响其拥有的窗口。

嗯?没有穿过啊?为什么?先动脑想想半分钟。
那是因为我们的实验不够严谨,现在在主窗口WM_PAINT消息的处理中加入一个Debug内容:

关于WS_CLIPSIBLINGS属性,下文将提到。好,就这样,大家看看运行效果:

WS_CLIPSIBLINGS   Clips child windows relative to each other; that is,
when a particular child window receives a paint message, the
WS_CLIPSIBLINGS style clips all other overlapped child windows out of
the region of the child window to be updated. (If WS_CLIPSIBLINGS is
not given and child windows overlap, when you draw within the client
area of a child window, it is possible to draw within the client area of
a neighboring child window.) For use with the 
WS_CHILD style only.

图片 9

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图