(转)使用GradientFill实现控件颜色渐变

1、使用的函数

GradientFill

  函数功能:该函数填充矩形和三角形结构。
  函数原型:BOOL GradientFill(HDC hdc, CONST PTRIVERTEX pVertex, DWORD dwNumVertex, CONST PVOID pMesh, DWORD dwNumMesh, DWORD dwMode);
  参数:
  hdc:指向目标设备环境的句柄。
  pVertex:指向TRIVERTEX结构数组的指针,该数组中的每项定义了三角形顶点。
  dwNumVertex:顶点数目。
  pMesh:三角形模式下的GRADIENT_TRIANGLE结构数组,或矩形模式下的GRADIENT_RECT结构数组。
  dwNumMesh:参数pMesh中的成员数目(这些成员是三角形或矩形)。
  dwMode:指定倾斜填充模式。该参数可以包含下列值,这些值的含义为:
  GRADIENT_FILL_RECT_H:在该模式下,两个端点表示一个矩形。该矩形被定义成左右边界具有固定颜色(由TRIVERTEX结构指定)。GDI从上至下插入颜色,并填充内部区域。
  GRADIENT_FILL_RECT_V:在该模式下,两个端点表示一个矩形。该矩形定义其顶部和底部边界的颜色为固定值(通过TRIVERTEX结构指定),GDI从顶至底部边界插入颜色,并填充内部区域。
  GRADIENT_FILL_TRIANGLE:在该模式下,TRIVERTEX结构数组以及描述单个三角形的数组索引序列被传给GDI。GDI在三角形顶点之间进行线性插值,并填充内部区域。在24和32位/像素模式下,绘图是直接进行。在16、8、4和1位/像素模式中进行抖动处理。
  返回值:如果函数执行成功,那么返回值为TRUE;如果函数执行失败,则返回值为FALSE。
  Windows NT:若想获得更多错误信息,请调用GetLastError函数。
  备注:若想在矩形区域中加入一些平滑的阴影(底纹),请用三角形的三个顶点调用GradientFill函数。CDI将进行线性插值,并填充矩形区域。在绘制矩形时可能使用两种阴影模式在水平模式中,矩形从左至右开始变暗,在垂直模式中则是从上至下进行。
  GradientFill函数使用网眼法(mesh method)来表示要绘制对象的端点。所有传给GradientFill的顶点都存储在pVertex数组中。参数pMesh指定了这些顶点如何连接形成一个对象。当填充矩形时,pMesh指向一个GRADIENT_RECT结构数组。每一个GRADIENT_RECT结构指定了pVertex数组中两个顶点的索引值,这两个顶点形成一个矩形的左上角和右下角坐标。

  在填充三角形情况下,pMesh指向的是GRADIENT_TRIANGLE结构数组。每一个GRADIENT_TRIANGLE结构指定了pVertex数组中的3个顶点,这三个顶点形成一个三角形。

2、实现

参考CodeProject上的Stataic代码

CPP文件代码

#include "stdafx.h"
#include "GradientStatic.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CGradientStatic

BEGIN_MESSAGE_MAP(CGradientStatic, CStatic)
//{{AFX_MSG_MAP(CGradientStatic)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CGradientStatic message handlers


CGradientStatic::CGradientStatic()
{
m_bVertical = FALSE;
m_iLeftSpacing = 10;
clLeft = GetSysColor(COLOR_ACTIVECAPTION);
clRight = GetSysColor(COLOR_BTNFACE);
clText = GetSysColor(COLOR_CAPTIONTEXT);

m_iAlign = 0;

hinst_msimg32 = LoadLibrary( "msimg32.dll" );
hinst_msimg32 = NULL;
m_bCanDoGradientFill = FALSE;
  
if(hinst_msimg32)
{
   m_bCanDoGradientFill = TRUE;  
   dllfunc_GradientFill = ((LPFNDLLFUNC1) GetProcAddress( hinst_msimg32, "GradientFill" ));
}
}

CGradientStatic::~CGradientStatic()
{
FreeLibrary( hinst_msimg32 );
}

//this function will be used only if msimg32.dll library is not available
void CGradientStatic::DrawGradRect(CDC *pDC, CRect r, COLORREF cLeft, COLORREF cRight, BOOL a_bVertical)
{
CRect stepR;      // rectangle for color's band
COLORREF color;     // color for the bands
float fStep;

if(a_bVertical)
   fStep = ((float)r.Height())/255.0f; 
else
   fStep = ((float)r.Width())/255.0f; // width of color's band

for (int iOnBand = 0; iOnBand < 255; iOnBand++) 
{
   // set current band
   if(a_bVertical)
   {
    SetRect(&stepR,
     r.left, 
     r.top+(int)(iOnBand * fStep),
     r.right, 
     r.top+(int)((iOnBand+1)* fStep)); 
   }
   else
   {
    SetRect(&stepR,
     r.left+(int)(iOnBand * fStep), 
     r.top,
     r.left+(int)((iOnBand+1)* fStep), 
     r.bottom); 
   }

   // set current color
   color = RGB((GetRValue(cRight)-GetRValue(cLeft))*((float)iOnBand)/255.0f+GetRValue(cLeft),
    (GetGValue(cRight)-GetGValue(cLeft))*((float)iOnBand)/255.0f+GetGValue(cLeft),
    (GetBValue(cRight)-GetBValue(cLeft))*((float)iOnBand)/255.0f+GetBValue(cLeft));
   // fill current band
   pDC->FillSolidRect(stepR,color);
}
}


void CGradientStatic::OnPaint() 
{
CPaintDC dc(this); // device context for painting

CRect rect;
GetClientRect(&rect);

if(m_bCanDoGradientFill) //msimg32.dll library is loaded
{

   TRIVERTEX rcVertex[2];
   rcVertex[0].x=rect.left;
   rcVertex[0].y=rect.top;
   rcVertex[0].Red=GetRValue(clLeft)<<8; // color values from 0x0000 to 0xff00 !!!!
   rcVertex[0].Green=GetGValue(clLeft)<<8;
   rcVertex[0].Blue=GetBValue(clLeft)<<8;
   rcVertex[0].Alpha=0x0000;
   rcVertex[1].x=rect.right; 
   rcVertex[1].y=rect.bottom;
   rcVertex[1].Red=GetRValue(clRight)<<8;
   rcVertex[1].Green=GetGValue(clRight)<<8;
   rcVertex[1].Blue=GetBValue(clRight)<<8;
   rcVertex[1].Alpha=0;
  
   GRADIENT_RECT rect;
   rect.UpperLeft=0;
   rect.LowerRight=1;
  
   // fill the area 
   dllfunc_GradientFill( dc,rcVertex,2,&rect,1, m_bVertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H);
  
}
else
{
   //msimg32.dll is not available. Let's use our own code to display gradient background.
   //This code is very simple and produces worse gradient that function from the library - but works!
   DrawGradRect(&dc,rect,clLeft,clRight,m_bVertical);
}

//let's set color defined by user
::SetTextColor(dc,clText);

HFONT hfontOld;
CFont* pFont = GetFont();
CString m_sTEXT;
GetWindowText(m_sTEXT);

if(pFont)
   hfontOld = (HFONT)SelectObject(dc.m_hDC, (HFONT)pFont->m_hObject);

::SetBkMode(dc, TRANSPARENT);
GetClientRect(&rect);

if(m_iAlign == 1) // center
   ::DrawText(dc, m_sTEXT, -1, &rect, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
else if(m_iAlign == 0) // left
{
   rect.left+=m_iLeftSpacing;
   ::DrawText(dc, m_sTEXT, -1, &rect, DT_SINGLELINE|DT_VCENTER|DT_LEFT);
}
else //right
{
   rect.right-=m_iLeftSpacing;
   ::DrawText(dc, m_sTEXT, -1, &rect, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);
}

if(pFont)
   ::SelectObject(dc.m_hDC, hfontOld);
}


void CGradientStatic::SetReverseGradient()
{
COLORREF cTemp = clLeft;
clLeft = clRight;
clRight = cTemp;
}

void CGradientStatic::SetWindowText(LPCSTR a_lpstr)
{
CStatic::SetWindowText(a_lpstr);
Invalidate();
}

头文件代码

typedef UINT (CALLBACK* LPFNDLLFUNC1)(HDC,CONST PTRIVERTEX,DWORD,CONST PVOID,DWORD,DWORD);

class CGradientStatic : public CStatic
{
// Construction
public:
CGradientStatic();
virtual ~CGradientStatic();
void SetWindowText(LPCSTR a_lpstr);
void SetColor(long cl) {clLeft=cl;};
void SetGradientColor(long cl) {clRight=cl;};
void SetTextColor(long cl) {clText=cl;};
void SetReverseGradient();
void SetLeftSpacing(int iNoOfPixels) { m_iLeftSpacing = iNoOfPixels; };
void SetTextAlign(int iAlign ) { m_iAlign = iAlign; }; //0 - left, 1 - center, 2 -right
void SetVerticalGradient(BOOL a_bVertical = TRUE) { m_bVertical = a_bVertical; };

static void DrawGradRect(CDC *pDC, CRect r, COLORREF cLeft, COLORREF cRight, BOOL a_bVertical);

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CGradientStatic)
//}}AFX_VIRTUAL


// Generated message map functions
protected:
CString m_sTEXT;
int m_iLeftSpacing;
long clLeft;
long clRight;
long clText;
int m_iAlign;
HINSTANCE hinst_msimg32;
BOOL m_bCanDoGradientFill;
BOOL m_bVertical;
LPFNDLLFUNC1 dllfunc_GradientFill;

//{{AFX_MSG(CGradientStatic)
afx_msg void OnPaint();
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

3、使用

把控件对应的CStatic替换为上面的类,就可以使用了

Note:其实所有用到渐变的地方,都可以使用渐变函数,上面的代码稍微修改就可以了,比如实现菜单栏的分割线的渐变,就是使用上面的代码,只不过地方是响应Windows的OwnerDraw事件了,就是自己描画分割线。


转自:http://hi.baidu.com/liuchen12061/blog/item/8e705e3c9daa67ce9f3d628e.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值