分享
 
 
 

为你的程序换个皮肤

王朝vc·作者佚名  2006-01-17
窄屏简体版  字體: |||超大  

为你的程序换个皮肤

作者/Kilo

下载源代码

(C)CopyRight, 2003-2004, IRS, All Rights Reserved

目前这方面的小软件很多,我一直就想做这么一个东东,但是一直苦于时间有限,一直都没有做。最近一段时间,我发现这些方面的东西越来越多,而且都没有源代码,一些家伙在网站上给出这样那样的示例,其实都是在为自己的产品做广告,实在有违开源的思想。

最近终于有了一段假期,反正没什么事做就来试试,经过一段时间的学习和摸索,终于实现了一段简单的程序。现在我就给出一个简单的例子和解释,让大家明白这是一个怎么回事,教你如何利用这个技术给一个按钮换肤?

以前我们一直利用重载一个类的办法来实现丰富多彩的个性化控件,如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,发布你的后继开发,贴出你的心得。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有