VC++界面编程之--自定义进度条(CProgressBar)皮肤


1.起因

我经常在PS设计网站和游戏界面,看到带条纹形状的进度条,看起来比较酷。所以决定实现一个带滚动效果的条纹进度条。

经过一段时间的尝试之后,完成了如下效果图,且是带有滚动效果的。

实现步骤:

1.素材

各大素材网站都有界面素材,比较出名的是站酷,从上面下载一份素材,尝试用PS截取你想要的图片吧。

我下了一份界面素材,如下图:

这些素材都是PSD分层的,可以省去抠图的时间,再说咱们也不是专业的PS大神,省省抠图的冲动吧。

经过对界面重新更改颜色后,我得到了如下三张图片:

1. 进度条背景图:

2.进度条:

3.进度条条纹,因条纹是白色的,所以为了方便讲解,我将其背景填充为黄色的。实际效果时背景色为透明色。

2.实现

因我们的进度条是图片格式的,在很多界面编程情况下,需要对其拉伸,所以得用一个特殊的方法,对图片进行拉伸,以达到不会失真的效果。

进图条图片是带圆角的矩形,所以我们需要将两边带圆角的图片,先裁切出来,然后在拉伸中间的图片即可。当然,中间的图片也是通过裁切和拼接,以达到拉伸的效果。

编程示意图如下,把裁切过的图片进行拼接,即可达到拉伸的效果,且不会失真(我将裁切图片分开了点空白距离,以便看清):

实现的代码如下:

程序根据输入的nCorner来对左右两边的图片进行裁切,然后先画左边的图像,再画中间的图像,最后再画右边的图像。中间的图像会依照实际的尺寸进行裁切,以达到拉伸的效果。注意这里的拉伸只是水平拉伸,并没有垂直拉伸。

	void StretchWidthImage(Graphics& g, Image* pImage, Rect& rcDest, REAL nCorner = 1.0F)
		{
			if (pImage == NULL || rcDest.Width <= 0 || nCorner <= 0)
			{
				return;
			}

			// rcDest's X and Y is relative coordinate.
			REAL nImageWidth	= (REAL)pImage->GetWidth();
			REAL nImageHeight	= (REAL)pImage->GetHeight();
			REAL nStretchLength	= (REAL)(nImageWidth - 2 * nCorner);
			REAL X				= (REAL)rcDest.X;
			REAL Y				= (REAL)rcDest.Y;
			REAL nLength		= (REAL)(rcDest.Width - 2 * nCorner);

			// Draw left corner.
			g.DrawImage(pImage, RectF(X, Y, nCorner, nImageHeight), 
				0, 0, nCorner, nImageHeight, UnitPixel);

			// If rect length less than image length,
			// Using rect length for real drawing length.
			REAL nRealLength = nStretchLength;
			if (nLength < nStretchLength)
			{
				nRealLength = nLength;
			}

			// Draw middle, stretch the length.
			REAL nLeftIndex		= nCorner + X;
			REAL nRightIndex	= nCorner + nRealLength + X;
			REAL nDrawLength	= nRealLength;
			while (TRUE)
			{
				g.DrawImage(pImage, RectF(nLeftIndex, Y, nDrawLength, nImageHeight), 
					nCorner, 0, nStretchLength, nImageHeight, UnitPixel);

				// If length equal 0 means all middle image has finished drawing.
				nLength -= nDrawLength;
				if (nLength <= 0)
				{
					break;
				}

				if (nLength < nDrawLength)
				{
					nDrawLength = nLength;
				}

				// Move drawing left Index.
				nLeftIndex	= nRightIndex;
				nRightIndex += nDrawLength;
			}

			// Draw right corner.
			g.DrawImage(pImage, RectF(nRightIndex, Y, nCorner, nImageHeight), 
				nImageWidth - nCorner, 0, nCorner, nImageHeight, UnitPixel);
		}
如果你输入的nCorner比实际图像的左边椭圆的半径要小,就会出现以下裁切不完整的情况,所以你可以根据目测,来指定一个稍大的nCorner值就好了。

3.实现条纹及滚动效果

条纹是按照一定的间距,在进度条表面依次进行绘制的,为了不让条纹的绘制超出进度条的范围,所以我用了SetClip函数,来设定绘制范围。代码实现如下:

	// Draw progress bar stripe.
	BOOL DrawStripe(Graphics& g)
	{
		if (m_rcProg.Width <= 0)
		{
			return FALSE;
		}

		g.SetClip(m_pathProg.m_pPath);
		int nLeftIndex = (int)( -(m_imgStripe.GetWidth()) + m_nLeftIndex );
		// Draw stripe.
		for (int nIndex = nLeftIndex; nIndex < m_rcProg.Width; nIndex += m_nStripeSpace)
		{
			Rect rc(nIndex, m_rcProg.Y, (int)m_imgStripe.GetWidth(), (int)m_imgStripe.GetHeight());
			g.DrawImage(m_imgStripe.m_pImage, rc);
		}
		return TRUE;
	}
这里我将条纹的起始绘制位置,设为了一个负数,以让条纹绘制从进度条最上边开始,且负数可以用作滚动效果的开始位置,如果你的滚动效果从0开始,那么将会导致下面这个情况,条纹开始脱离进度条了:


4.本文代码及工程文件

http://download.csdn.net/detail/renstarone/5773021


  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值