65.9K
CodeProject 正在变化。 阅读更多。
Home

Adobe 风格的滑块控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (6投票s)

2012年1月3日

CPOL

2分钟阅读

viewsIcon

30538

downloadIcon

1096

自定义标准滑块控件, 使其外观类似于 Adobe 风格的滑块控件

引言

adobeslider.JPG

本文介绍如何通过 Windows 自身提供的自定义绘制功能来定制 Windows 标准滑块控件。虽然这里绘制了一个 Adobe Photoshop 风格的滑块控件,但用户可以根据指南创建具有自定义外观的漂亮滑块控件。

背景

在一个项目中,我被要求提供一个外观类似于 Adobe 部分截取控件,但同时具有滑块所有 API 和功能的控件。因此,我处理了滑块的 NM_CUSTOMDRAW 反射消息,并创建了这个外观不错的(虽然我自己这么认为)滑块。

使用代码

从资源中在对话框中放置一个滑块控件,通过 MFC 向导为滑块添加一个成员变量,并将类名更改为 CAdobeSliderCtrl,以便在父对话框的头文件中看起来像这样。

CAdobeSliderCtrl m_adobeSliderCtrl; 

猜猜怎么着,你完成了。现在你的滑块应该看起来像顶部的图像中的那个。

关注点

void CCustomDrawSliderCtrl::OnCustomDraw ( NMHDR* pNMHDR, LRESULT* pResult)
{		
	NMCUSTOMDRAW nmcd = *(LPNMCUSTOMDRAW) pNMHDR;

	UINT drawStage = nmcd.dwDrawStage;
	UINT itemSpec = (UINT)nmcd.dwItemSpec;
	
	switch ( drawStage )
	{
		case CDDS_PREPAINT:
			// most important of the drawing stages must return CDRF_NOTIFYITEMDRAW or else we will not get further 
			// NM_CUSTOMDRAW notifications for this drawing cycle we also return CDRF_NOTIFYPOSTPAINT 
			// so that we will get post-paint notifications		
			*pResult = CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT ;
		break;

		case CDDS_PREERASE:		// Before the erase cycle begins
		case CDDS_POSTERASE:	// After the erase cycle is complete
		case CDDS_ITEMPREERASE:	// Before an item is erased
		case CDDS_ITEMPOSTERASE:	// After an item has been erased
			*pResult = CDRF_DODEFAULT;
		break;

		case CDDS_ITEMPREPAINT:
			switch (itemSpec)
			{
				case TBCD_CHANNEL:					
					*pResult = CDRF_SKIPDEFAULT;					
				break;

				case TBCD_TICS:					
					*pResult = CDRF_DODEFAULT;
				break;

				case TBCD_THUMB:
				{										
					CDC* pDC = CDC::FromHandle( nmcd.hdc );
					Draw(pDC, &nmcd);

					*pResult = CDRF_SKIPDEFAULT;
				}
				break;
			}
		break;

		case CDDS_ITEMPOSTPAINT:	// After an item has been drawn
			switch ( itemSpec )
			{				
				case TBCD_TICS:					
					*pResult = CDRF_DODEFAULT;
				break;

				case TBCD_THUMB:
					*pResult = CDRF_DODEFAULT;	
				break;
			}

		break;
	}	
}

我想引起读者对上面粘贴的代码的注意。

看看如何处理项目预绘和后绘,以及调用 Draw 的位置。这与滑块的标准编码不同,但这是一个轻松实现滑块任何类型绘制覆盖的技巧。

为了解决从拇指内部调用整个滑块控件绘制的非标准问题,Draw 函数有一个小技巧,如下面的代码注释中清晰地指出了。

void CCustomDrawSliderCtrl::Draw(CDC *pDC, LPNMCUSTOMDRAW lpcd)
{	
	CRect rc;
	GetWindowRect(rc);
	GetClientRect(rc);
	// The first drawing is to make sure the thumb area is painted properly with the background
	// and the edges
	OnDraw(pDC, rc);	

	// The next drawing is to make sure the control is drawn properly covering the whole client area
	CClientDC dc(this);
	OnDraw(&dc, rc);	
}

我希望你能猜到 CCustomDrawSliderCtrl 为滑块控件的完全所有者绘制提供了一个基础,这应该由派生控件在 OnDraw 可重写方法中完成,就像在 CAdobeSliderCtrl 中完成的那样(当然是从 CCustomDrawSliderCtrl 继承而来)。

因此,本文的目的是提供一个根据你的意愿绘制滑块的基础。当然,除了极少数特定情况外,我个人不建议过多更改标准 Windows 控件的绘制,除非绝对必要。

历史

文章发布日期:2012 年 1 月 3 日(怎么样.. 以一篇新文章开始新的一年 :) !!)

© . All rights reserved.