[ATL/WTL]_[Gdiplus]_[实现按钮的阴影效果]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/infoworld/article/details/83501708

场景

  1. WTL开发时, 由于界面需要, 很多按钮都是奇形怪状的. 比如卡片形状, 圆角矩形等等. 只要是点击能响应一个事件的, 我们都可以看做是一个异形按钮. 其中让按钮呈现立体效果, 动画效果等一直是实现自定义按钮的难点.

  2. 系统按钮一般是带3D效果的按钮. 我们这里实现自带阴影效果的按钮一样具备很好的特效, 阴影按钮特别适合在面积比较大的卡片按钮上.

说明

  1. Gdiplus窗口实现阴影效果可以参考 VC++界面编程之–阴影窗口的实现详解. 这个效果不合适自定义的按钮,因为按钮并不是顶层窗口. 实际上可以参考绘制阴影的部分在按钮的部分区域绘制阴影效果,这样也是可以的, 这样也省了创建额外窗口的开销.

  2. Gdiplus实现阴影的其中一种方式是使用PathGradientBrush, 也就是渐变的画刷来绘制阴影部分. 其实也很好理解, 因为阴影部分其实也是模糊的黑色效果. 在借助graphics.ExcludeClip来排除正常的按钮部分, 只绘制阴影区域, 能很好的不影响正常的区域.

例子

图示
系统按钮
在这里插入图片描述

阴影按钮
在这里插入图片描述

// Create round rect path.
void CreateRoundRect(Gdiplus::GraphicsPath& m_pPath,
	Gdiplus::Rect rect, int cornerRadius)
{
	// https://docs.microsoft.com/en-us/windows/desktop/api/gdipluspath/nf-gdipluspath-graphicspath-addarc%28inreal_inreal_inreal_inreal_inreal_inreal%29
	m_pPath.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
	m_pPath.AddLine(rect.X + cornerRadius, rect.Y, rect.GetRight() - cornerRadius * 2, rect.Y);
	m_pPath.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
	m_pPath.AddLine(rect.GetRight(), rect.Y + cornerRadius * 2, rect.GetRight(), rect.Y + rect.Height - cornerRadius * 2);
	m_pPath.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
	m_pPath.AddLine(rect.GetRight() - cornerRadius * 2, rect.GetBottom(), rect.X + cornerRadius * 2, rect.GetBottom());
	m_pPath.AddArc(rect.X, rect.GetBottom() - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
	m_pPath.AddLine(rect.X, rect.GetBottom() - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
	m_pPath.CloseFigure();
}

void DrawShadow(CDC& dc,Gdiplus::Graphics& graphics)
{
	Gdiplus::Rect rect_button(600,400,128, 50);
	Gdiplus::GraphicsPath m_pPath;
	Gdiplus::Pen pen(Gdiplus::Color(255,0,0),2);
	CreateRoundRect(m_pPath,rect_button, 8);

	Gdiplus::Rect rcShadow = rect_button;
	rcShadow.Width+=6;
	rcShadow.Height+=6;
	Gdiplus::GraphicsPath shadow_path;
	CreateRoundRect(shadow_path,rcShadow,8);

	Gdiplus::PathGradientBrush brShadow(&shadow_path);
	Gdiplus::Color clrShadow[3] = {Gdiplus::Color::Transparent,Gdiplus::Color(255, 0, 0, 0),
		Gdiplus::Color(255, 0, 0, 0)};
	int nCount = 3;

	Gdiplus::REAL szPos[3] = {0.0F, 0.1F,1.0F};
	brShadow.SetInterpolationColors(clrShadow, szPos, nCount);

	Gdiplus::Region region(&m_pPath);
	graphics.ExcludeClip(&region);
	graphics.FillPath(&brShadow,&shadow_path);

	graphics.ResetClip();
	graphics.DrawPath(&pen,&m_pPath);
}

LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);
	Gdiplus::Graphics graphics(dc);
	// 注意, 得添加这句实现绘制图形时有反锯齿效果. 不然用Gdiplus和Gdi都有锯齿.
	graphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
	//DrawText(dc,graphics);
	//DrawRectangle(dc,graphics);
	DrawShadow(dc,graphics);

	return 0;
}

参考

VC++界面编程之–阴影窗口的实现详解
PathGradientBrush::SetInterpolationColors method

猜你喜欢

转载自blog.csdn.net/infoworld/article/details/83501708
今日推荐