您的位置:首页 > 其它

skinmagic对VC中程序窗口的换肤

2011-03-10 22:24 218 查看
一直以来没怎么关心过程序界面的开发,最近想对程序界面的美化学习一下。

下面先展示一下这次开发所实现的效果:





程序我已经上传到CSDN上面了,同时我所使用的skinmagic包也已经上传。

程序主要实现了:

1. 窗口的基本美化:菜单,窗口

2. 换肤菜单

3. 主窗口和子窗口同时换肤

下面先引用别人的我认为相当全面的一个总结(引自:http://cool.worm.blog.163.com/blog/static/64339006200952503917995/):

文件说明

SkinMagicLib.h 必须的头文件,请添加到工程中。

SkinMagic.lib + SkinMagic.dll 动态链接库配套使用

编译时需要在工程中添加SkinMagic.dll,程序运行时需要SkinMagic.dll

以下版本的编译出来的程序运行时不再依赖SkinMagic.dll

SkinMagicLibMD6.lib 静态链接库,用于VC6的Release版编译

SkinMagicLibMT6.lib 静态链接库,用于VC6的Debug版编译

使用方法

将所需文件放到你的VC6工程目录下,养成良好的编程习惯:

把SkinMagicLib.h放到使用的VC6工程目录下的include目录中;

把SkinMagicLibMT6.lib, SkinMagicLibMD6.lib放到使用的VC6工程目录下lib目录中;

把*.smf皮肤文件放到VC6工程的目录下skin目录中;

在StdAfx.h中添加

#include "SkinMagicLib.h"

在工程设置中添加对应的库

Win32 Release中填上SkinMagicLibMD6.lib

Win32 Debug中填上SkinMagicLibMT6.lib

用文本编辑器打开工程的rc文件,在里面加入

/////////////////////////////////////////////////////////////////////////

//

// SKINMAGIC

//

XPBLUE SKINMAGIC DISCARDABLE "skin//xpblue.smf"

CORONA SKINMAGIC DISCARDABLE "skin//corona.smf"

XPGREAN SKINMAGIC DISCARDABLE "skin//xpgrean.smf"

XPLUS SKINMAGIC DISCARDABLE "skin//x-plus.smf"

DEVIOR SKINMAGIC DISCARDABLE "skin//Devior.smf"

XPSTEEL SKINMAGIC DISCARDABLE "skin//xpsteel.smf"

KROMO SKINMAGIC DISCARDABLE "skin//Kromo.smf"

添加完毕后,会发现资源视图中会多了一个“SkinMagic”的目录。

在InitInstance()函数的开始处添加初始化SkinMagic资源的代码。

VERIFY(1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL, NULL, NULL));

在InitInstance()函数中加载皮肤文件并设置程序皮肤。

CROSDlg dlg;

m_pMainWnd = &dlg;

VERIFY( 1 == LoadSkinFromResource( AfxGetInstanceHandle() , "DEVIOR" ,"SKINMAGIC") ); //加载静态皮肤资源

// VERIFY( 1 == LoadSkinFile("corona.smf") ); //动态加载皮肤文件

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd, "Dialog" ));

VERIFY( 1 == SetDialogSkin( "Dialog" ) );

int nResponse = dlg.DoModal();

if (nResponse == IDOK)

{

// TODO: Place code here to handle when the dialog is

// dismissed with OK

}

else if (nResponse == IDCANCEL)

{

// TODO: Place code here to handle when the dialog is

// dismissed with Cancel

}

在ExitInstance()函数中释放SkinMagic资源

ExitSkinMagicLib(); //释放SkinMagic资源

问题处理


将 #include "SkinMagicLib.h" 添加在StdAfx.h中可能出现问题

SkinMagicLibMT6.lib(MultiMonitor.obj) : error LNK2001: unresolved external symbol _xEnumDisplayMonitors@16

SkinMagicLibMT6.lib(MultiMonitor.obj) : error LNK2001: unresolved external symbol

_xGetMonitorInfo@8

SkinMagicLibMT6.lib(MultiMonitor.obj) : error LNK2001: unresolved external symbol

_xMonitorFromWindow@8

SkinMagicLibMT6.lib(MultiMonitor.obj) : error LNK2001: unresolved external symbol

_xMonitorFromPoint@12

SkinMagicLibMT6.lib(MultiMonitor.obj) : error LNK2001: unresolved external symbol

_xMonitorFromRect@8

Debug/ROS.exe : fatal error LNK1120: 5 unresolved externals

解决方法:将其移到使用SkinMagic时的主文件中,加其头文件如下

#include "SkinMagicLib.h"

#pragma warning(disable:4706)

#define COMPILE_MULTIMON_STUBS

#include <multimon.h>

#pragma warning(default:4706)

"LIBCMT.lib"和其他的一些libs有冲突,这个有可能是本人程序遇见的问题,未证实

LIBCMT.lib(crt0dat.obj) : error LNK2005: _exit already defined in msvcrtd.lib(MSVCRTD.dll)

LIBCMT.lib(crt0dat.obj) : error LNK2005: __exit already defined in msvcrtd.lib(MSVCRTD.dll)

LIBCMT.lib(atox.obj) : error LNK2005: _atoi already defined in msvcrtd.lib(MSVCRTD.dll)

LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_z already defined in msvcrtd.lib(cinitexe.obj)

LIBCMT.lib(crt0init.obj) : error LNK2005: ___xc_a already defined in msvcrtd.lib(cinitexe.obj)

LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_z already defined in msvcrtd.lib(cinitexe.obj)

LIBCMT.lib(crt0init.obj) : error LNK2005: ___xi_a already defined in msvcrtd.lib(cinitexe.obj)

LIBCMT.lib(winxfltr.obj) : error LNK2005: __XcptFilter already defined in msvcrtd.lib(MSVCRTD.dll)

LIBCMT.lib(strtol.obj) : error LNK2005: _strtoul already defined in msvcrtd.lib(MSVCRTD.dll)

msvcrtd.lib(MSVCRTD.dll) : error LNK2005: __setmbcp already defined in LIBCMT.lib(mbctype.obj)

LINK : warning LNK4098: defaultlib "msvcrtd.lib" conflicts with use of other libs; use /NODEFAULTLIB:library

LINK : warning LNK4098: defaultlib "LIBCMT" conflicts with use of other libs; use /NODEFAULTLIB:library

LIBCMT.lib(crt0.obj) : error LNK2001: unresolved external symbol _main

Debug/ROS.exe : fatal error LNK1120: 1 unresolved externals

解决方法:问题的原因上面已经指出,就是红色那一句,默认的"msvcrtd.lib"和其他的一些libs有冲突,可以用/NODEFAULTLIB:library
设置屏蔽掉默认的libcmt.lib


在Project中打开Project Setting设置对话框,选择Link选中Category旁边下拉框的Input项。

在Ignore Libraries下面输入libcmt.lib,将此屏蔽。

程序编译Release版时出错

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _InitMultipleMonitorStubs already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xGetSystemMetrics@4

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xMonitorFromPoint@12

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xMonitorFromRect@8

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xMonitorFromWindow@8

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xGetMonitorInfo@8

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _xEnumDisplayMonitors@16

already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_fMultiMonInitDone already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnEnumDisplayMonitors already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnGetMonitorInfo already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnMonitorFromPoint already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnMonitorFromRect already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnMonitorFromWindow already defined in ROS.obj

SkinMagicLibMD6.lib(MultiMonitor.obj) : error LNK2005: _g_pfnGetSystemMetrics already defined in ROS.obj

Release/ROS.exe : fatal error LNK1169: one or more multiply defined symbols found

解决方法:在 Project/Setting/Link/General中的 Project Options: 加入 /FORCE:MULTIPLE
即可。

也可以代码实现,在stdafx.h中添加代码

#pragma comment(linker, "/FORCE:MULTIPLE")

#pragma comment(linker, "/OPT:NOREF")

使用SkinMagic时,对话框程序显示菜单

解决方法:

当然要有其菜单项信息,这里程序使用的资源ID是 IDR_MENU

首先屏蔽掉App中InitInstance()函数中的

// VERIFY( 1 == SetDialogSkin( "Dialog" ) );

在主窗体中的头文件.h中定义一个菜单

CMenu m_menu;

在主窗体中的执行文件.cpp中的OnCreate()函数中建立菜单

m_menu.LoadMenu(IDR_MENU);

SetMenu( &m_menu );

在主窗体中的执行文件.cpp中的OnInitDialog()初始化对话框函数中设置SkinMagic外肤

VERIFY( 1 == SetWindowSkin( m_hWnd , "Dialog" ));

EnableWindowScrollbarSkin( m_hWnd , SB_BOTH );

一些自定义控件的处理,在使用对话框程序时,有一些自定义的控件,比如说加载的自定义按钮、静态文本框等等,在使用SkinMagic时后,他们将无法正常使用。

解决方法:解决很简单,在SkinMagic中移除它即可。

// CStaticTrans m_staticCarSpeed;

// m_staticCarSpeed 是自定义一个显示车速的静态文本控件

VERIFY( 1 == RemoveWindowSkin( m_staticCarSpeed.m_hWnd ) );

文档视图的初始化

解决方法:由于极少在文档中使用SkinMagic,只简单列出示例

BOOL CxxxApp::InitInstance()

{

//...

VERIFY( 1 == InitSkinMagicLib( AfxGetInstanceHandle(), NULL, NULL, NULL ) );

VERIFY( 1 == LoadSkinFile( _T("corona.smf") ) );

m_pMainWnd->ShowWindow(m_nCmdShow);

m_pMainWnd->UpdateWindow();

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , _T("MainFrame") ));

SetControlTooltip( pMainFrame->m_wndToolBar.m_hWnd , _T("ToolBar") );

VERIFY( 1 == SetDialogSkin( _T("Dialog") ) );

//...

}

在子窗口重载WM_CREATE在其中添加代码

SetWindowSkin( m_hWnd , _T("MainFrame") );

========================传说中的分割线==========================

当然网上还有很多这样的教程:

2.0版

把corona.smf,SkinMagicLibMD6.lib,SkinMagicLib.h考入程序文件夹中.

在stdafx.h中添加代码

#include "SkinMagicLib.h"

//#pragma comment(lib, "SkinMagicLibMD6Trial.lib")

#pragma comment(lib, "SkinMagicLibMD6.lib")

/* 当在Project/Setting/General中选择"Use MFC in a Static Library"时,

需要以下两条语句:

*/

#pragma comment(linker, "/FORCE:MULTIPLE")

#pragma comment(linker, "/OPT:NOREF")

在主文件添加头文件

#define COMPILE_MULTIMON_STUBS

#include "multimon.h"

在BOOL CMDIDemoApp::InitInstance()开头添加

VERIFY( 1 == InitSkinMagicLib( AfxGetInstanceHandle(), _T("Demo") ,

NULL,

NULL ) );

VERIFY( 1 == LoadSkinFile( _T("corona.smf") ) );

在尾部 pMainFrame->ShowWindow(m_nCmdShow);

pMainFrame->UpdateWindow();

之前添加

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , _T("MainFrame") ));

SetControlTooltip( pMainFrame->m_wndToolBar.m_hWnd , _T("ToolBar") );

VERIFY( 1 == SetDialogSkin( _T("Dialog") ) );

之后就编译成功了,继续为子窗口重载WM_CREATE或WM_INITDIALOG

在其中添加代码SetWindowSkin( m_hWnd , _T("MainFrame") );

2.2版

1、下载SkinMagic Toolkit,复制SkinMagicTrial.dll、SkinMagicTrial.lib、SkinMagicLib.h以及皮肤文件corona.smf至项目的目录下。(这样比较简单J,可以在这下载。)

2、在stdafx.h中加入头文件和库的引用,如下:

#i nclude "SkinMagicLib.h"

#pragma comment(lib, "SkinMagicTrial.lib")

l 使用SkinMagic

1、 初始化SkinMagic库:

int __stdcall InitSkinMagicLib( HINSTANCE hInstance,

LPCTSTR lpApplication ,

LPCTSTR lpReserved1,

LPCTSTR lpReserved2 );

在 CxxxApp::InitInstance()中加入初始化SkinMagic库的代码:

VERIFY( 1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL, NULL, NULL));

2、调入皮肤文件:

皮肤的调用有两种方法,一是直接从皮肤文件中调用,另一种方法是从资源文件中调用,分别说明如下:

1) 从皮肤文件中调用皮肤:

int __stdcall LoadSkinFile( LPCTSTR lpSkinFile );

2)从资源文件中调用皮肤:

int __stdcall LoadSkinFromResource(HMODULE hModule,

  LPCTSTR lpSkinName ,

LPCTSTR lpType);

现在CxxxApp::InitInstance()中的代码如下:

BOOL CxxxApp::InitInstance()

{

VERIFY( 1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL, NULL, NULL));

VERIFY( 1 == LoadSkinFile("corona.smf"));

AfxEnableControlContainer();

//…..下略

}

3、将皮肤应用到程序上

int __stdcall SetWindowSkin( HWND hWnd , LPCTSTR lpSkinName );

 int __stdcall SetDialogSkin( LPCTSTR szSkinName );

1)对话框程序代码位置:

BOOL CxxxApp::InitInstance()

{

//...上略

m_pMainWnd = &dlg;

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

VERIFY( 1 == SetDialogSkin( "Dialog" ) );

int nResponse = dlg.DoModal();

//…下略

}

2)文档视图程序代码的位置

BOOL CxxxApp::InitInstance()

{

//…上略

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

VERIFY( 1 == SetDialogSkin( "Dialog" ) );

return TRUE;

}

4、释放SkinMagic资源

void __stdcall ExitSkinMagicLib();

重载应用程序的ExitInstance()函数,添加如下代码:

int CxxxApp::ExitInstance()

{

ExitSkinMagicLib();

return CWinApp::ExitInstance();

}

1.把:SkinMagicLib.h,DETOURS.lib,SkinMagicLib.lib三个文件拷入工程目录

注意:如果你的工程是使用的共享DLL,那么你要选择共享DLL的SkinMagicLib.h,SkinMagicLib.lib

如果你的程序是使用的静态连接DLL的,那你选择静态的SkinMagicLib.h,SkinMagicLib.lib

否则连接时出问题...

2."工程"->添加到工程->文件->将DETOURS.lib,SkinMagicLib.lib添加到工程中

3.在stdafx.h中,加入#include "SkinMagicLib.h"

4.将皮肤文件拷入工程目录中的"rec"文件夹中

5.工作空间中切换到ResourceView,右键选"引入",在弹出的对话框中找到皮肤文件,选中将其插入到工程文件中

在接下来的对话框中起个文件夹名:"SKINMAGIC",将皮肤文件插入到该文件夹中

6.皮肤文件插入到工程后,可在ResourceView中找到皮肤文件的ID,右键选属性,改ID名字

7.在ClassView中找到CxxxAPP类.然后找到InitInstance()函数,然后在

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

之前加入以下代码:

VERIFY( 1 == InitSkinMagicLib( AfxGetInstanceHandle(), "Demo" ,

NULL,

NULL ) );

VERIFY( 1 == LoadSkinFromResource( AfxGetInstanceHandle() , "XPGREEN" ,"SKINMAGIC") );

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

VERIFY( 1 == SetDialogSkin( "Dialog" ) );

8.在CxxxAPP类中,右键选AddVirtualFunction,然后添加ExitInstance()函数,在其中加入:

ExitSkinMagicLib();

9.编译,连接,执行...OK,皮肤添加完成...

使用SkinMagic Toolkit美化界面

[准备工作]

1、将SkinMagicTrial.dll放置在调试目录

2、设置库文件目录,在项目[连接器]的[附加依赖项]中加入库SkinMagicTrial.lib

3、在项目的stdafx.h文件中加入头文件 #include "SkinMagicLib.h"

[创建过程]

1、初始化SkinMagic库:


要使用SkinMagic,这一步必不可少。在应用程序类的InitInstance()函数中行加入如下代码(粗体部分):

CWinApp::InitInstance();

VERIFY( 1 == InitSkinMagicLib(AfxGetInstanceHandle(), NULL ,

NULL, NULL ));

说明:


int InitSkinMagicLib( //初始化SkinMagic工具库

HINSTANCE hInstance, //应用程序句柄

char* szApplication , //皮肤文件中定义的应用程序名,置为NULL即可

char* szRegCode, //SkinMagic的使用注册码。若无置为NULL

char* szReserved2 //保留位,为NULL

);

2、调入皮肤文件:



皮肤的调用有两种方法,一是直接从皮肤文件中调用,另一种方法是从资源文件中调用,分别说明如下:

1)从皮肤文件中调用皮肤:紧接上句,加入如下代码

VERIFY( 1 == LoadSkinFile("corona.smf"));

2)从资源文件中调用皮肤:

VERIFY(1 == LoadSkinFromResource(NULL,"FUTURA","skin"));

//资源名称带有双引号

int LoadSkinFromResource(

HMODULE hModule, //包含皮肤文件的模块句柄,若NULL表面在本模块中

char* lpSkinName , //皮肤资源的名称

char* lpType); //资源的类型

3、为窗口添加皮肤:



1)为标准窗口(拥有标题栏、系统菜单、可变大小等特征,比如文档/视图结构和有菜单的对话框)添加皮肤,通常用于主窗口。在应用程序类的InitInstance()函数的底部加入如下代码:

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

说明:



int SetWindowSkin(

HWND hWnd, //要使用皮肤的窗口句柄

char* lpSkinName //为skinFrameWnd对象指定的名称

);

2)为对话框添加皮肤



在对话框显示之前调用,通常在应用程序初始化函数中调用

VERIFY( 1 == SetWindowSkin( m_pMainWnd->m_hWnd , "MainFrame" ));

VERIFY( 1 == SetDialogSkin( "Dialog" ) );

m_pMainWnd->ShowWindow(SW_SHOW);

m_pMainWnd->UpdateWindow();

说明:


int SetDialogSkin(

char* lpSkinName //为skinFrameWnd对象指定的名称

);

使用该函数后,以后程序创建的对话框都将使用该皮肤,但对话框大小不可变。

3)为单个对话框窗口添加皮肤,例如在对话框视图中:重载对话框视图的创建函数OnCreate,加入如下代码:

VERIFY( 1 == SetSingleDialogSkin( m_hWnd, "Dialog" ) );

EnableWindowScrollbarSkin( m_hWnd , SB_BOTH );

说明:


int SetSingleDialogSkin(

HWND hWnd, //要使用皮肤的窗口句柄

char* lpSkinName //为skinFrameWnd对象指定的名称

);

int EnableWindowScrollbarSkin( //为滚动条添加皮肤

HWND hWnd, //要使用皮肤的窗口句柄

int* fnBar //要使用皮肤的滚动条,SB_BOTH表明是横竖都是用皮肤

);

4、释放SkinMagic资源

重载应用程序的ExitInstance()函数,添加如下代码:

ExitSkinMagicLib();

======================传说中的分割线==============================

下面讲下主窗口和子窗口同时换肤的实现:

这个需要建两个函数,如图所示,一个是oncreate,一个是onpaint。第一个很好理解,每次新建一个子窗口时就会自动执行oncreate里面的代码,第二个是在程序刚开始运行时就初始化最开始的子窗口。



添加完这两个函数之后,分别写入如下内容:

SetWindowSkin( m_hWnd , _T("MainFrame") );

这样就实现了同时换肤的效果了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: