渲染层的封装和隔离:BkSkin
控件的绘制工作基本都封装到了Skin里面,如果控件对应的Skin存在的话,那么会按照Skin的描述进行绘制,在CBkWindow的DrawBkgnd方法中,使用Skin进行了绘制:
CBkSkinBase*pSkin = BkSkin::GetSkin(m_style.m_strSkinName);
if(pSkin)
{
pSkin->Draw(dc, m_rcWindow, m_dwState);
}
看一下Skin的继承关系:
对于CBkSkinBase类,只需要绘制的区域,绘制的状态以及绘制的DC就可以。CBkSkinBase是一个虚基类,从CBkSkinBase继承的子类需要实现Draw方法,在这个方法中实现具体的绘制操作。
同时CBkSkinBase类也提供了一下这些工具方法,用来辅助绘制操作:
HorzExtendDraw
FrameDraw
GradientFillRectV
GradientFillRectH
GradientFillRectV
GradientFillRectH
我们来看个CBkSkinButton类,当然主要看Draw方法:
virtual void Draw(CDCHandle dc, CRect rcDraw, DWORD dwState)
{
CPen penFrame;
CRect rcBg = rcDraw;
dc.FillSolidRect(rcDraw, m_crBg); //填充背景颜色
rcBg.DeflateRect(2,2);
if (BkWndState_Disable== (BkWndState_Disable & dwState)) //如果Disable状态,不进行绘制
{
}
else
GradientFillRectV(
dc, rcBg,
IIF_STATE3(dwState,m_crBgUpNormal, m_crBgUpHover,m_crBgUpPush),
IIF_STATE3(dwState,m_crBgDownNormal, m_crBgDownHover,m_crBgDownPush));
penFrame.CreatePen( //创建画笔,用于边框绘制
PS_SOLID,
1,
m_crBorder
);
HPEN hpenOld = dc.SelectPen(penFrame);
HBRUSH hbshOld= NULL, hbshNull= (HBRUSH)::GetStockObject(NULL_BRUSH); //空画刷
hbshOld = dc.SelectBrush(hbshNull);
dc.Rectangle(rcDraw); //绘制矩形边框
dc.SelectBrush(hbshOld);
dc.SelectPen(hpenOld);
}
在上面的绘制中使用了控件的状态,控件状态定义如下:
// State Define
enum{
BkWndState_Normal = 0x00000000UL,
BkWndState_Hover = 0x00000001UL,
BkWndState_PushDown = 0x00000002UL,
BkWndState_Check = 0x00000004UL,
BkWndState_Invisible = 0x00000008UL,
BkWndState_Disable = 0x00000010UL,
};
这个IIF_STATE3是个宏定义,对于指定的状态,返回相应的背景,具体如下:
#define IIF_STATE2(the_state,normal_value, hover_value)\
(((the_state) & BkWndState_Hover) ? (hover_value): (normal_value))
#define IIF_STATE3(the_state,normal_value, hover_value,pushdown_value) \
(((the_state) & BkWndState_PushDown) ? (pushdown_value): IIF_STATE2(the_state,normal_value, hover_value))
#define IIF_STATE4(the_state,normal_value, hover_value,pushdown_value, disable_value)\
(((the_state) & BkWndState_Disable) ? (disable_value): IIF_STATE3(the_state,normal_value, hover_value,pushdown_value))