Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1852491
  • 博文数量: 909
  • 博客积分: 4000
  • 博客等级: 上校
  • 技术积分: 12260
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-06 20:50
文章分类

全部博文(909)

文章存档

2008年(909)

我的朋友

分类:

2008-05-06 22:08:04

一起学习
VC 工程中加入 SplashScreen 原理释解


作者:Abbey

下载源代码

摘要
  本文旨在剖析VC 工程中加入 SplashScreen 的原理,并给出在VC MFC(exe)工程中加入 SplashScreen 的步骤。

关键字 SplashScreen,原理

环境:
Windows 98SE/2000,VC 6.0
  SplashScreen - 我们使用 Word 之类的软件在启动的短暂时间里就会看到它的身影。它通常用以在程序启动时显示程序及用户名称,版权信息等。我也不知道它准确的名称是什么(是闪屏吗?),就这样称呼吧。也许你也想在自己的工程里加入这样的特性,本文将以创建实际工程的方式逐步剖析其实现原理。

注意
:为避免实际所使用工程名给类或对象名带来的干扰,除非特别说明,在本文中将使用基类名如CWinApp、CMainFrame、CDialog来代替实际工程中的相应派生类名进行描述。
  Visual C 是一个相当强大的C 开发工具,它内嵌了对SplashScreen的支持。但是在MFC EXE类型工程中只是对带有主框架类的SDI或MDI工程提供了这一支持,基于对话框类的工程则被排除在外。现在让我们开始吧。第一步是在SDI工程中加入SplashScreen。
  首先利用AppWizard生成一个SDI工程,除了其中Docking ToolBar必须选择外(我认为这是MFC的一个Bug,当然这与本文讨论的SplashScreen没有关系),其他的文档-视图支持、状态条之类的都可以不要,这样可以尽量减少无用的代码。
  通过IDE中的菜单Project->Add to Project->Components and Controls,我们就可以从Visual C Components中选择Splash Screen这个组件插入工程。



  在点击了"Insert"后会弹出一个如下图所示的对话框,这是设置插入该工程中的SplashScreen的类名、显示用位图的ID及文件名,采用缺省值即可。



  通过以上几步的操作,就会在工程目录下生成Splash.CPP和Splash.H文件,这便是CSplashWnd类的实现文件与头文件。同时工程中CWinApp与CMainFrame类中的部分代码也会被修改,以实现CSplashWnd窗口的消息处理。
  接着我们来看看 CSplashWnd 类的声明与主要的代码(已经过删减):

//类的声明

class CSplashWnd : public CWnd

{

	CSplashWnd();

	~CSplashWnd();

	virtual void PostNcDestroy();	



	static void EnableSplashScreen(BOOL bEnable = TRUE);

	static void ShowSplashScreen(CWnd* pParentWnd = NULL);

	static BOOL PreTranslateAppMessage(MSG* pMsg);

	BOOL Create(CWnd* pParentWnd = NULL);

	void HideSplashScreen();



	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);

	afx_msg void OnPaint();

	afx_msg void OnTimer(UINT nIDEvent);

	

	CBitmap m_bitmap;	  //SplashScreen窗口显示用的位图对象

	static BOOL c_bShowSplashWnd; //是否要显示SplashScreen的标志量

	static CSplashWnd* c_pSplashWnd;

};		
//是否使用SplashScreen
void CSplashWnd::EnableSplashScreen(BOOL bEnable)

{

	c_bShowSplashWnd = bEnable;

}

//创建CsplashWnd对象,并调用Create()创建窗口
void CSplashWnd::ShowSplashScreen(CWnd* pParentWnd)

{

	//如果不要显示SplashScreen或SplashWnd对象已经被创建则返回

	if (!c_bShowSplashWnd || c_pSplashWnd != NULL)

		return;

		

	c_pSplashWnd = new CSplashWnd;

	

	if (!c_pSplashWnd->Create(pParentWnd))

		delete c_pSplashWnd;

	else

		c_pSplashWnd->UpdateWindow();

}

//装入SplashScreen欲显示位图,通过CreateEx()激发OnCreate()完成窗口创建与设置
BOOL CSplashWnd::Create(CWnd* pParentWnd)

{

	if (!m_bitmap.LoadBitmap(IDB_SPLASH))

		return FALSE;



	BITMAP bm;

	m_bitmap.GetBitmap(&bm);



	return CreateEx(0, 
AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
NULL,
WS_POPUP | WS_VISIBLE,
0,
0,
bm.bmWidth,
bm.bmHeight,
pParentWnd->GetSafeHwnd(),
NULL);
}
//销毁窗口,刷新框架
void CSplashWnd::HideSplashScreen()

{

	DestroyWindow();

	AfxGetMainWnd()->UpdateWindow();

}

//利用窗口创建结构创建窗口,并设置定时器在750ms后触发OnTimer()
int CSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

	if (CWnd::OnCreate(lpCreateStruct) == -1)

		return -1;

	

	CenterWindow(); //窗口居中显示

	SetTimer(1, 750, NULL); //设置定时器

	

	return 0;

}

//将键盘和鼠标消息传递给CSplashWnd对象,以销毁窗口
BOOL CSplashWnd::PreTranslateAppMessage(MSG* pMsg)

{

	if (c_pSplashWnd == NULL)

		return FALSE;

	

	if (pMsg->message == WM_KEYDOWN ||

	    pMsg->message == WM_SYSKEYDOWN ||

	    pMsg->message == WM_LBUTTONDOWN ||

	    pMsg->message == WM_RBUTTONDOWN ||

	    pMsg->message == WM_MBUTTONDOWN ||

	    pMsg->message == WM_NCLBUTTONDOWN ||

	    pMsg->message == WM_NCRBUTTONDOWN ||

	    pMsg->message == WM_NCMBUTTONDOWN)

		{

			c_pSplashWnd->HideSplashScreen();

			return TRUE;

		}

	return FALSE;

}



void CSplashWnd::OnTimer(UINT nIDEvent)

{

	HideSplashScreen();

}

再看看CWinApp和CMainFrame类中发生了什么样的改变:
(1)在CWinApp::InitInstance()中调用CSplashWnd::EnableSplashScreen()设置c_bShowSplashWnd;
在PreTranslateMessage()中调用CSplashWnd::PreTranslateAppMessage(),将键盘和鼠标消息传递给CSplashWnd对象,从而进一步调用CSplashWnd::HideSplashScreen()实现SplashScreen窗口的自身销毁。
(2)在CMainFrame对象的OnCreate()中调用CSplashWnd::ShowSplashScreen()创建一个静态的SplashScreen窗口对象c_pSplashWnd,并设置其父窗口为CMainFrame。在这个过程中,CSplashWnd自身会通过创建来设置一个定时器,然后定时器在第一个周期触发时便调用HideSplashScreen()销毁自己。
(3) 而CMainFrame对象的窗口创建消息则是由CWinApp对象在InitInstance()中通过
m_pMainWnd->ShowWindow()调用触发的。
  整个过程可以用下图表示,基本原理就是由CMainFrame来创建CSplashWnd,然后由CSplashWnd自己的定时器触发定时消息来销毁窗口。所以 CSplashWnd 的加入与SDI还是MDI都没有关系。



  第二步,我们再来看看如何在基于对话框的工程中加入 SplashScreen。
通过对以上SDI工程中加入SplashScreen原理的剖析,我想大家也想到如何在基于对话框的工程中加入这一特性了。其实质就是由CDialog类完成SDI工程中CMainFrame类的工作,实现步骤如下:
(1)利用ClassWizard为CMyDialog添加WM_CREATE消息的处理函数OnCreate();(这里使用CMyDialog是为了与函数内的基类名CDialog区别。)
int CMyDialog::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

	if (CDialog::OnCreate(lpCreateStruct) == -1)

		return -1;

	CSplashWnd::ShowSplashScreen(this);



	return 0;

}        
(2)利用ClassWizard为CWinApp添加消息转发处理函数PreTranslateMessage();
BOOL CWinApp::PreTranslateMessage(MSG* pMsg)

{

	if (CSplashWnd::PreTranslateAppMessage(pMsg))

		return TRUE;

	

	return CWinApp::PreTranslateMessage(pMsg);

}

(3)CWinApp::InitInstance()中加入如下调用: CSplashWnd::EnableSplashScreen(TRUE);
(4)当然你还需要将上一个SDI工程中生成的Splash.CPP与Splash.H文件拷贝到当前工程目录下,并利用Project->Add to Project->Files将这两个文件引入工程。同时还要在CWinApp与CMainFrame的实现文件中#include "Splash.H"。
(5)然后在资源管理器里添加一个ID为IDB_SPLASH的位图。由于VC 的IDE只能显示256色以下的位图,所以如果你想显示一幅真彩色的位图,就请用Import方式导入一幅预先制作好的位图。当然VC 会提示位图已经成功导入,只是无法在IDE的位图编辑器中显示,而在程序运行时就会显示了。如果你想象Word那样显示用户名等信息,可以在CSplashWnd::Create()中装载位图之后增加自己的代码来修改位图。
  通过以上这几步操作,我们就完成了在基于对话框的工程中加入SplashScreen的工作。清楚了吗? 下载本文示例代码


VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解VC 工程中加入 SplashScreen 原理释解
阅读(372) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~