为你的程序换个皮肤

来源:互联网 发布:ssh命令连接linux 编辑:程序博客网 时间:2023/06/05 19:04
 

目前这方面的小软件很多,我一直就想做这么一个东东,但是一直苦于时间有限,一直都没有做。最近一段时间,我发现这些方面的东西越来越多,而且都没有源代码,一些家伙在网站上给出这样那样的示例,其实都是在为自己的产品做广告,实在有违开源的思想。
  最近终于有了一段假期,反正没什么事做就来试试,经过一段时间的学习和摸索,终于实现了一段简单的程序。现在我就给出一个简单的例子和解释,让大家明白这是一个怎么回事,教你如何利用这个技术给一个按钮换肤?
  以前我们一直利用重载一个类的办法来实现丰富多彩的个性化控件,如GuiToolkit、CJ60LIB,都是这样的工具,使用起来还是要在程序中插入大量的语句,这样做一方面增加了程序的复杂性,另一方面也增加了程序高度的难度。当然现在也有像SkinMagic、EasySkin这样的工具,只需要在你的程序里增加两行代码就可以实现对常用控件的换肤,但是这些工具都没有源代码,对于想学习开发的人来说实在没什么帮助。为了让大家都了解这项技术,我决定开发一个这样的程序,并公布源程序,希望有兴趣的朋友都来看看,动手做做,同时欢迎大家公开你的源程序,和大家一起分享你的成功和快乐。
  首先,来给一个程序换肤,我们必须得到程序的句柄,然后给程序挂钩。下面的一段代码就实现了挂钩功能。

BOOL  IRStartup( HINSTANCE hModule, DWORD dwThreadID )
{
globalWndHookEx = SetWindowsHookEx(
WH_CALLWNDPROC, (HOOKPROC) IRCallWndProc, hModule, dwThreadID );

return TRUE;
}
这也是像SkinMagic一类工具的初始化函数。当然在退出时也要释放钩子的。
BOOL  IRComplete( void )
{
UnhookWindowsHookEx( globalWndHookEx );

return TRUE;
}

接下来,就是IRCallWndProc这个回调函数的编写,这是至关重要的一个环节,这个函数就是对所要换肤的类对象进行了监视,并改变其消息处理函数,实现换肤的目的。
LRESULT CALLBACK IRCallWndProc( int nCode, WPARAM wParam, LPARAM lParam )
{
PCWPSTRUCTpcs = (PCWPSTRUCT) lParam;
HWNDhWnd = pcs->hwnd;

if( hWnd ) {
charsClassName[201] = "/0";

GetClassName( hWnd, sClassName, 200 );
if( strcmp( sClassName, "Button" ) == 0 ) {
CWnd*pWnd = CWnd::FromHandle( hWnd );
DWORDdwStyle = pWnd->GetStyle();
if( dwStyle == 0x50010000 ) {
WNDPROCWndProc;
WndProc = (WNDPROC) GetWindowLong( hWnd, GWL_WNDPROC );
if( CButtonExt::m_cWndProc != NULL && /
WndProc != CButtonExt::m_cWndProc )
{
return CallNextHookEx( globalWndHookEx,
nCode,
wParam,
lParam );
}
if( WndProc != (WNDPROC) CButtonExt::DefWindowProc ) {
WndProc = (WNDPROC) SetWindowLong(
hWnd,
GWL_WNDPROC,
(LONG) CButtonExt::DefWindowProc );
CButtonExt::m_cWndProc = WndProc;
}
}
}
}

return CallNextHookEx( globalWndHookEx, nCode, wParam, lParam );
}
这样就对按钮的消息进行了挂钩处理了,就可以重新来绘制按钮了。紧接着就是给出按钮控件的绘制方法,我是用一个类来实现的,都是使用的静态函数直接调用的。
#define STATUS_BUTTON_NORMAL0x00000000
#define STATUS_BUTTON_HOVER0x00000001
#define STATUS_BUTTON_DOWN0x00000002

class CButtonExt
{
public:
CButtonExt() {}
~CButtonExt() {}

static UINTm_nStatus;
static WNDPROCm_cWndProc;

static LRESULT DefWindowProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
CWnd*pWnd = NULL;
CPointpoint;
pWnd = CWnd::FromHandle( hWnd );

switch( message )
{
case WM_PAINT:
return OnPaint( pWnd );
break;

case WM_LBUTTONDOWN:
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
return OnLButtonDown( pWnd, 0, point );
break;

case WM_LBUTTONUP:
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
return OnLButtonUp( pWnd, 0, point );
break;

case WM_LBUTTONDBLCLK:
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
return OnLButtonDblClk( pWnd, 0, point );
break;

case WM_MOUSEMOVE:
point.x = LOWORD(lParam);
point.y = HIWORD(lParam);
return OnMouseMove( pWnd, 0, point );
break;

default:
break;
}

return CallWindowProc( m_cWndProc, hWnd, message, wParam, lParam );
}

static LRESULT OnLButtonDown( CWnd *pWnd, UINT nFlags, CPoint point ) {
m_nStatus = STATUS_BUTTON_DOWN;
pWnd->Invalidate();
pWnd->UpdateWindow();

return TRUE;
}

static LRESULT OnLButtonUp( CWnd *pWnd, UINT nFlags, CPoint point ) {
if( m_nStatus != STATUS_BUTTON_NORMAL ) {
m_nStatus = STATUS_BUTTON_NORMAL;
pWnd->Invalidate();
pWnd->UpdateWindow();
SendMessage( pWnd->GetParent()->m_hWnd,
WM_COMMAND,
pWnd->GetDlgCtrlID(),
(LPARAM) (pWnd->m_hWnd) );
}

return TRUE;
}

static LRESULT OnLButtonDblClk( CWnd *pWnd, UINT nFlags, CPoint point ) {
return TRUE;
}

static LRESULT OnMouseMove( CWnd *pWnd, UINT nFlags, CPoint point ) {
HRGN hRgn = CreateRectRgn( 0, 0, 0, 0 );
pWnd->GetWindowRgn( hRgn );

BOOL bIn = PtInRegion( hRgn, point.x, point.y );
if( bIn ) {
if( m_nStatus == STATUS_BUTTON_DOWN ) return TRUE;
if( m_nStatus != STATUS_BUTTON_HOVER ) {
m_nStatus = STATUS_BUTTON_HOVER;
pWnd->Invalidate();
pWnd->UpdateWindow();
pWnd->SetCapture();
}
} else {
if ( m_nStatus == STATUS_BUTTON_HOVER ) {
m_nStatus = STATUS_BUTTON_NORMAL;
pWnd->Invalidate();
pWnd->UpdateWindow();
ReleaseCapture();
}
}
DeleteObject( hRgn );

return TRUE;
}

static LRESULT OnPaint( CWnd *pWnd ) {
CPaintDCdc(pWnd);
CStringcs;
RECTrc;
CFontFont;
CFont*pOldFont;
CBrushBrush;
CBrush*pOldBrush;
CPenPen;
CPen*pOldPen;
POINTpt;
pt.x = 2;
pt.y = 2;

dc.SetBkMode( TRANSPARENT );
Font.CreateFont( 12, 0, 0, 0, FW_HEAVY, 0, 0, 0, ANSI_CHARSET, /
OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, /
VARIABLE_PITCH | FF_SWISS, "MS Sans Serif" );
pOldFont = dc.SelectObject( &Font );

if( m_nStatus == STATUS_BUTTON_DOWN ) {
Brush.CreateSolidBrush( RGB( 160, 160, 160 ) );
Pen.CreatePen( PS_SOLID, 1, RGB( 100, 100, 100 ) );
dc.SetTextColor( RGB( 50, 50, 250 ) );
} else if( m_nStatus == STATUS_BUTTON_HOVER ) {
Brush.CreateSolidBrush( RGB( 60, 60, 180 ) );
Pen.CreatePen( PS_SOLID, 1, RGB( 0, 0, 0 ) );
dc.SetTextColor( RGB( 250, 250, 50 ) );
} else if( m_nStatus == STATUS_BUTTON_NORMAL ) {
Brush.CreateSolidBrush( RGB( 240, 240, 240 ) );
Pen.CreatePen( PS_SOLID, 1, RGB( 120, 120, 120 ) );
dc.SetTextColor( RGB( 50, 50, 50 ) );
}
pOldBrush = dc.SelectObject( &Brush );
pOldPen = dc.SelectObject( &Pen );
pWnd->GetClientRect( &rc );
dc.RoundRect( &rc, pt );

HRGN hRgn = CreateRectRgn( rc.left, rc.top, rc.right, rc.bottom );
pWnd->SetWindowRgn( hRgn, TRUE );
DeleteObject( hRgn );

pWnd->GetWindowText( cs );
dc.DrawText( cs, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE );

dc.SelectObject( pOldFont );
dc.SelectObject( pOldBrush );
dc.SelectObject( pOldPen );

return TRUE;
}

static LRESULT OnEraseBkgnd( CWnd *pWnd, CDC *pDC ) {
return TRUE;
}
};
UINTCButtonExt::m_nStatus = STATUS_BUTTON_NORMAL;
WNDPROCCButtonExt::m_cWndProc = NULL
  程序结构还是很清楚的,这时做一些简单的说明。m_nStatus用来标志按钮的状态,m_cWndProc用来保存系统的消息处理函数地址。其他就不用说了吧。 最后,就是如何在程序中使用的问题了。调用方法其实很简单,在CSkinApp类的InitInstance()函数中加入这样的一句话:
IRStartup( GetModuleHandle( NULL ), GetCurrentThreadId() );
在CSkinApp类的ExitInstance()中加入这样的一句话:
IRComplete();
  这样就实现了对按钮的换肤,是不是很简单啊,我只是做了一个简单的实现,还有很多工作需要大家一起来做,希望有兴趣的朋友一起来做,有什么问题请到 http://www.110i.net上发问,同时也希望大家把你们的作品公布出来,SkinDemo的开发网站就在http://www.110i.net,发布你的后继开发,贴出你的心得。
原创粉丝点击
热门问题 放学后 http://hi.baidu.com/realrice/blog/item/4e75cecb804 HRN算法python shadowrocket 蜜桃传媒 StockbrokerGrapevine 股票经纪人 股票jjr 图像金字塔 腿上汗毛孔没开都是点点怎么办 脸蛋澡巾擦破了怎么办 婴儿后背用擦澡巾擦红了怎么办 搓澡皮肤搓破了怎么办 搓背搓的脖子红痒怎么办 上班迟到1个小时怎么办 想家想的都哭怎么办 想学手艺被骗学费怎么办 小腿肚后面筋和肌肉压痛怎么办 尿道囗和屁股眼中间长疮怎么办? 2个多月的宝宝蛋蛋上有个包怎么办 幼儿园睡觉自己摸下身玩怎么办 猫猫打喷嚏有透明液体怎么办 夏季穿运动鞋出了脚气怎么办 脚底长了刺瘊子怎么办 凉鞋前面踢破了怎么办 尖头鞋前面折了怎么办 月子里宝宝蛋蛋破皮怎么办 军人在训练时想上侧所怎么办 被白蚂蚁咬了怎么办 被蚂蚁咬了起包怎么办 脚踢了石头肿了怎么办 脚大拇指踢肿了怎么办 被骨头咯到了疼怎么办 被开水烫着了疼怎么办 鞋子上踩了口香糖怎么办 鞋底踩到口香糖干了怎么办 鞋子不小心踩到口香糖怎么办 站久了膝盖痛怎么办 站久了脚底板痛怎么办 蛇疮好了以后痛怎么办 站久了脚趾痛怎么办 心脏被踢了一脚怎么办 从马背上摔下来怎么办 小孩蛋蛋碰撞后有积液怎么办 小孩蛋蛋大小不一样有积液怎么办 对派出所的笔录不服怎么办 蛋蛋让尿淹了发红有小红瘩达怎么办 手被皮筋弹肿了怎么办 手被皮筋勒肿了怎么办 皮筋把手挤肿了怎么办