文档章节

[win32] 实现窗口阴影的3种方法

Michael_BJFU
 Michael_BJFU
发布于 2016/10/12 15:26
字数 577
阅读 489
收藏 0

windows开发中经常用DUI方式进行绘制,要自己处理窗口的全部绘制任务,包括阴影。那么就面临一个问题:阴影窗口是半透明窗口;这就意味着需要使用Layer窗口来绘制阴影,接下来就有了一个比较通用的方法:

1、创建一个Layer窗口绘制阴影
创建真正窗口
需要处理的消息包括WM_WINDOWPOSCHANGED, WM_CLOSE,

void C*****Wnd::OnWindowPosChanged(LPWINDOWPOS lpWndPos)
{
    if ((lpWndPos->flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOSIZE | SWP_NOMOVE))
    {
        CRect rc;
        GetWindowRect(&rc);
        CSize sz = m_layerShadow.GetPreferredSize();
        m_layerShadow.SetWindowPos(NULL, rc.left - sz.cx / 2, rc.top - sz.cy / 2,
        rc.Width() + sz.cx, rc.Height() + sz.cy, SWP_NOZORDER | SWP_NOACTIVATE |         SWP_SHOWWINDOW);
        m_layerShadow.Refresh();
    }
}

创建阴影

HWND CreateLayerWnd(HWND hParent)
{
   DWORD dwFlags = WS_EX_LAYERED | WS_EX_NOACTIVATE | WS_EX_TRANSPARENT;
   Create(hParent, CRect(0, 0, 0, 0), 0, WS_POPUP, dwFlags);
}

创建Layer窗口时,第一个要注意的点是WS_EX_NOACTIVATE,系统不会改变foreground窗口的activate状态。但是同时要处理WM_MOUSEACTIVATE,msdn中有表述:


The WS_EX_NOACTIVATE value for dwExStyle prevents foreground activation by the system. To prevent queue activation when the user clicks on the window, you must process the WM_MOUSEACTIVATE message appropriately. 

 所以一般会加一个窗口类,来处理这个消息;

class CLayerWrapper : public CWindowImpl<CLayerWrapper>
{
public:

	CLayerWrapper()	{}
	virtual ~CLayerWrapper() {}

	void Show(HWND hWnd, CRect rc, bool bActive, DWORD dwExStyle);
	void Refresh();

	virtual void OnPaint(CDCHandle dc) = 0;

private:

	BEGIN_MSG_MAP_EX(CLayerWrapper)
		MSG_WM_SIZE(OnSize)
		MSG_WM_MOUSEACTIVATE(OnMouseActivate)
	END_MSG_MAP()

	void	OnSize(UINT nType, CSize size);
	int		OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message);

};
void CLayerWrapper::Show(HWND hWnd, CRect rc, bool bActive, DWORD dwExStyle)
{
	if (!IsWindow())
	{
		DWORD dwFlags = WS_EX_LAYERED;
		if (!bActive)
			dwFlags |= WS_EX_NOACTIVATE;
		Create(hWnd, rc, 0, WS_POPUP, dwFlags | dwExStyle);
	}
	DWORD dwFlags = SWP_SHOWWINDOW;
	if (!bActive)
		dwFlags |= SWP_NOACTIVATE;
	SetWindowPos(NULL, rc, dwFlags);
}

void CLayerWrapper::Refresh()
{
	CRect rc;
	GetWindowRect(rc);
	CLayeredMemDC MemDC;
	MemDC.CreateMemDC(rc.Width(), rc.Height());
	OnPaint((HDC)MemDC);
	CPoint pt(rc.left, rc.top);
	BLENDFUNCTION stBlend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
	::UpdateLayeredWindow(m_hWnd, NULL, &pt, &rc.Size(), MemDC, &CPoint(0, 0), 0, &stBlend, ULW_ALPHA);
}

void CLayerWrapper::OnSize(UINT nType, CSize size)
{
	Refresh();
}

int CLayerWrapper::OnMouseActivate(CWindow wndTopLevel, UINT nHitTest, UINT message)
{
	return MA_NOACTIVATE;
}

然后从LayerWrapper派生一下即可,这样在OnPaint中绘制阴影,Owner窗口为真正的窗口。

2、使用WS_THICKFRAME
加入这个属性,可以使用系统的边框、阴影,缺点是:用DUI绘制窗口时,大部分呢情况阴影都自己弄,另外无法处理异形窗口阴影

3、使用CS_DROPDOWN

这是一个class style,所以需要SetClassLong();

DWORD dwStyle = GetClassLong(m_hWnd, GCL_STYLE);
SetClassLong(m_hWnd, GCL_STYLE, dwStyle | CS_DROPSHADOW);

这种方法可以处理好WindowRgn的问题。
总结一下:通常情况下使用第一种方式,如果有异形窗口可以使用第3种,偷懒的情况下是用第二种。

© 著作权归作者所有

Michael_BJFU
粉丝 2
博文 14
码字总数 10021
作品 0
海淀
私信 提问
Qt之对话框淡出、飞入、最小化的动画实现

转自:https://www.cnblogs.com/swarmbees/p/7288885.html 一、效果展示   最近做了一个提示框消失的功能,觉着挺有意思,以前一直以为Qt子窗口不能做淡出效果,其实Qt的淡出功能已经帮我们...

shzwork
09/18
44
0
你可以知道的关于XMind的样式

XMind思维导图为用户提供了丰富的模板和快捷的图标及属性设置。那么,对于思维导图的样式与形式,我们该如何理解呢?   1. 画布属性   在XMind内,我们不仅可以逐一对每个主题的线条设置其...

xmind
2015/08/04
287
0
OpenCV学习:隐藏 Console 窗口

在VC++中使用OpenCV,一般是建立一个 win32 console application 项目,当运行此类程序的时候,默认情况下会有一个类似DOS窗口的console窗口,供程序与用户之间交互之用。 但是有时候我们只想...

heartfly
2010/10/25
934
1
[Beautifulzzzz的博客目录] 快速索引点这儿O(∩_∩)O~~,红色标记的是不错的(⊙o⊙)哦~

3D相关开发 [direct-X] 1、direct-X最小框架 [OpenGL] 1、环境搭建及最小系统 [OpenGL] 2、企业版VC6.0自带的Win32-OpenGL工程浅析 51单片机 [51单片机] 1602液晶显示控制代码 [51单片机] 1...

史迪奇2号
2017/08/01
0
0
Cef与MFC联合开发中,使用CFileDialog导致阻塞

使用cef_binary_3.2171.1979_windows32 和MFC,在VS2013环境下进行开发 错误再现流程 1、JS接收网页点击按钮事件, 2、使用Cef的V8Handler中的Excute转发消息到CefClient的OnProcessMessageR...

谯飞
2015/08/24
1K
0

没有更多内容

加载失败,请刷新页面

加载更多

自建redis笔记

自建redis笔记 最近在linux安装了一下redis,特做一些笔记! 本文先单节点启动redis,然后再进行持久化配置,在次基础上,再分享搭建主从模式的配置以及Sentinel 哨兵模式及集群的搭建 单节点...

北极之北
17分钟前
2
0
vue+element之多表单验证

方法一:利用promise var p1=new Promise(function(resolve, reject) { this.$refs[form1].validate((valid) => { if(valid){ ......

沉迷代码我爱学习
20分钟前
2
0
golang 1.13 errors 包 新函数介绍

引 这次 errors 包算重量级更新。很有更能把以前的一些设计模式给推到。下面聊下用法。 error 装包 以前返回一个错误,想要保存 error 链,还要定义结构体保存以前的 error 信息。感兴趣看下...

guonaihong
29分钟前
50
0
并发编程之线程池

一、线程池 1、什么是线程池 Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行任务的程序 都可以使用线程池。在开发过程中,合理地使用线程池能够带来3个好处。 第一:降...

codeobj
31分钟前
4
0
知识点总结思维导图模板分享,良心安利,建议收藏

思维导图经常被用在学习中,对大脑思维进行发散,对知识进行记忆。使用思维导图可以让知识更加简单更有层次。下面是利用思维导图所绘制的几款知识点总结思维导图模板,大家可以进行进行参考使...

干货趣分享
34分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部