WS_CLIPCHILDREN和WS_CLIPSIBLINGS

WS_CLIPCHILDREN样式从字面上可以理解成ClipChildren,裁减子窗口。

MSDN里的E文解释:Excludes the area occupied by child windows when drawing occurs within the parent window. This style is used when creating the parent window.

E文是一件困难的事,为了不让大家再重复我的痛苦,我就越俎代庖翻译一下:WS_CLIPCHILDREN样式主要是用于父窗口,也就是说当在父窗口绘制的时候,父窗口上还有一个子窗口,那么设置了这个样式的话,子窗口区域父窗口就不负责绘制。

那么按照MSDN的理解,可以用下面这幅图来表示:

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第1张图片

1‑1 WS_CLIPCHILDREN样式的初理解

1.1 WS_CLIPSIBLINGS

WS_CLIPSIBLINGS样式从字面上可以理解成ClipSiblings,裁减兄弟窗口。

MSDN里的E文解释:Clips child windows relative to each other; that is, when a particular child window receives a WM_PAINT message, the WS_CLIPSIBLINGS style clips all other overlapping child windows out of the region of the child window to be updated. If WS_CLIPSIBLINGS is not specified and child windows overlap, it is possible, when drawing within the client area of a child window, to draw within the client area of a neighboring child window.

中文意思是:子窗口间相互裁减。也就是说当两个窗口相互重叠时,设置了WS_CLIPSIBLINGS样式的子窗口重绘时不能绘制被重叠的部分。反之没有设置WS_CLIPSIBLINGS样式的子窗口重绘时是不考虑重叠不重叠,统统重绘。

1‑2 WS_CLIPSIBLINGS样式的初理解

3.做几个实验

3.1 验证 WS_CLIPCHILDREN

简单到什么程度呢?只需要在对话框的属性打个勾而已。

3‑1 如何设置对话框Clip Children属性

我们先做做第一个程序,这个程序唯一有点难的地方就在于需要继承一下CStatic类,然后重载一下OnPaint函数。

void MYStatic::OnPaint()

{

CPaintDC dc(this); // device context for painting

// TODO: Add your message handler code here

// 获得控件客户区矩形大小

CRect rect;

GetClientRect(rect);

// 绘制控件边框

dc.MoveTo(0,0);

dc.LineTo(rect.Width(),0);

dc.LineTo(rect.Width(),rect.Height());

dc.LineTo(0,rect.Height());

dc.LineTo(0,0);

// 绘制文本

    dc.TextOut(rect.Width()/2 - 5,rect.Height()/2 - 5,"Hello");

// Do not call CStatic::OnPaint() for painting messages

}

当我们不设置对话框的Clip children属性的时候,效果如下图所示:

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第2张图片

3‑2 效果图

   当设置了Clip children属性的时候,接下来是见证奇迹的时刻。^_^

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第3张图片

       3‑4 预想的效果图

3‑6控件的Tab顺序

发现结果很混乱,每回都得不到我想要的,具有随机性。甚至有的时候按照我的预想,有的时候则完全不管我的心情。哪怕我气的吹胡子瞪眼睛,也是枉然。

最常见的是这样一种情况,就是无论我设置不设置WS_CLIPSIBLINGS属性,当点击重绘图片控件的时候(m_pic.Invalidate(),效果都一如既往,先开始图片控件(pic)被自定义控件(custom)压盖,然后重绘之后,图片控件(pic)压盖自定义控件(custom)

 

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第4张图片

3‑5 一种错误图

经过一段时间的郁闷,我最终找到了问题之所在,是这样的一个结论:WS_CLIPSIBLINGS还和控件的叠加顺序有关。叠加顺序如果不对,你无法查看WS_CLIPSIBLINGS的效果。就上面的问题,我们可以在VC编辑器里查看到控件的叠加顺序。

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第5张图片

Pic控件是在custom控件的下方。(Tab OrderZ Order顺序是一致的)。这样设置不设置WS_CLIPSIBLINGS都无法看出效果。

但是改变控件的压盖顺序,令pic控件压盖在custom控件之上(实际上是改变Tab order顺序)

 

3‑7 控件的Tab顺序

这样就会出现预期的效果。当不设置WS_CLIPSIBLINGSpic控件会压盖custom控件,而当设置了该属性,则pic控件不会压盖custom控件,重叠的区域由custom控件自己绘制。

WS_CLIPCHILDREN和WS_CLIPSIBLINGS_第6张图片

3‑8 预期的效果

4.结论

好,到此为止,应该说点有结论的话了。

1           WS_CLIPCHILDREN样式主要是用于父窗口,也就是说当在父窗口绘制的时候,父窗口上还有一个子窗口,那么设置了这个样式的话,子窗口区域父窗口就不负责绘制。

2           所有的overlappedpopup风格的窗口,都有WS_CLIPSIBLINGS 属性。也就是说这类风格的窗口,你是去不掉WS_CLIPSIBLINGS 属性的,不会在它重叠的兄弟窗口绘图;

3           更进一步说明,WS_CLIPSIBLINGS只是用于子窗口(For use with the WS_CHILD style only.

       4 WS_CLIPSIBLINGS实际上还需要和控件的叠放顺序(z order)配合使用,才能看出明显的效果。

 

 

MFC强行刷新子窗口

当父窗体设置了 WS_CLIPCHILDREN 的属性后, 默认状态下,RedrawWindow InvalidateRect 不会导致子窗体重绘,因此,如果子窗体同时设置了 WS_EX_TRANSPARENT 属性,子窗体就会被父窗体刷没了。

解决的办法是 RedrawWindow 的时候添加 RDW_ALLCHILDREN 标志,强制子窗体也重绘,而不要使用默认的 RedrawWindow InvalidateRect(当然也包括 Invalidate)。

RedrawWindow(NULL, NULL, RDW_ALLCHILDREN);

 

你可能感兴趣的:(WS_CLIPCHILDREN和WS_CLIPSIBLINGS)