作者信息:罗树鹏 http://www.cnblogs.com/luoshupeng
由于笔者在实践过程中走了一些弯路,所以把这些情况记录下来,希望为后来者提供一些经验。
在VC6.0时代,可以通过组件为工程加入SplashScreen,具体方法是通过IDE中的菜单Project->Add to Project->Componentsand Controls,就可以从Visual C++ Components中选择Splash Screen这个组件插入工程。
但进入到VC. NET时代,这种方法就不行了,需要程序作者自己加入SplashScreen类,自己处理一些系统消息。下面笔者就把实践过程记录下来,并指出需要注意的地方。
一、 新建一个SplashScreen类,并声明成员和方法
新建基类为CWnd的CSplashWnd类(当然类名可以自由书写),并声明如下成员:
CBitmap m_bitmap; //加载SplashScreen图片用
static CSplashWnd*c_pSplashWnd; //CSplashWnd类的句柄,可以用来判定CSplashWnd是否已经创建或消毁
static BOOLc_bShowSplashWnd; //标识是否显示显示用来,静态成员需要在类外进行初始化
类成员一般声明为保护类型(protected)。接下来声明几个静态方法来处理这些成员:
static BOOLc_bShowSplashWnd; //标识是否显示显示用来,静态成员需要在类外进行初始化
static void ShowSplashScreen(CWnd* pParentWnd = NULL); //用来显示SplashScreen窗口
static BOOLPreTranslateAppMessage(MSG* pMsg); //用来处理一些消息 注意这里不是继承于CWnd类的PreTranslateMessage方法
这些方法一定要声明成公开类型的(public),因为要在外部调用这些方法。接下来再声明两个自定义方法:
BOOL Create(CWnd*pParentWnd = NULL); //创建窗口
void HideSplashScreen(void); //隐藏窗口
我把这些方法声明为保护类型(protected)。接下来再声明一些处理系统消息的函数:
virtual void PostNcDestroy();
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnPaint();
至此,类已经设计完毕。完整的头文件如下:
#pragma once
#include "afxwin.h"
//CSplashWnd
class CSplashWnd : public CWnd
{
DECLARE_DYNAMIC(CSplashWnd)
protected:
CSplashWnd();
public:
virtual~CSplashWnd();
protected:
CBitmap m_bitmap; //加载SplashScreen图片用
staticCSplashWnd* c_pSplashWnd; //CSplashWnd类的句柄,可以用来判定CSplashWnd是否已经创建或消毁
staticBOOL c_bShowSplashWnd; //标识是否显示显示用来,静态成员需要在类外进行初始化
public:
static void EnableSplashScreen(BOOL bEnable = TRUE); //用来设定c_bShowSplashWnd
static void ShowSplashScreen(CWnd* pParentWnd = NULL); //用来显示SplashScreen窗口
staticBOOL PreTranslateAppMessage(MSG* pMsg); //用来处理一些消息 注意这里不是继承于CWnd类的PreTranslateMessage方法
protected:
virtualvoid PostNcDestroy();
afx_msg intOnCreate(LPCREATESTRUCT lpCreateStruct);
afx_msg voidOnTimer(UINT_PTR nIDEvent);
afx_msg voidOnPaint();
BOOL Create(CWnd* pParentWnd = NULL); //创建窗口
voidHideSplashScreen(void); //隐藏窗口
DECLARE_MESSAGE_MAP()
};
二、 CSplashWnd类方法的实现
这里需要注意的事项是在析构函数中一定要把c_pSplashWnd成员置为NULL类型,否则程序收到消息后会出现异常。其它没有什么了,直接看代码吧。
//Splash.cpp : implementation file
//
#include "stdafx.h"
#include "Splash.h"
CSplashWnd*CSplashWnd::c_pSplashWnd;
BOOLCSplashWnd::c_bShowSplashWnd;
//CSplashWnd
IMPLEMENT_DYNAMIC(CSplashWnd,CWnd)
CSplashWnd::CSplashWnd()
{
}
CSplashWnd::~CSplashWnd()
{
ASSERT(c_pSplashWnd == this);
c_pSplashWnd = NULL;
}
BEGIN_MESSAGE_MAP(CSplashWnd,CWnd)
ON_WM_CREATE()
ON_WM_TIMER()
ON_WM_PAINT()
END_MESSAGE_MAP()
//CSplashWnd message handlers
voidCSplashWnd::EnableSplashScreen(BOOL bEnable/* =TRUE*/)
{
c_bShowSplashWnd = bEnable;
}
voidCSplashWnd::ShowSplashScreen(CWnd* pParentWnd/* =NULL*/)
{
//如果不要显示SplashScreen或SplashWnd对象已经被创建则返回
if (!c_bShowSplashWnd || c_pSplashWnd!=NULL)
{
return;
}
c_pSplashWnd = newCSplashWnd;
if ( !c_pSplashWnd->Create(pParentWnd))
{
deletec_pSplashWnd;
}
else
{
c_pSplashWnd->UpdateWindow();
}
}
BOOLCSplashWnd::PreTranslateAppMessage(MSG* pMsg)
{
if(c_pSplashWnd == NULL)
returnFALSE;
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();
returnTRUE;
}
returnFALSE;
}
void CSplashWnd::PostNcDestroy()
{
delete this;
}
intCSplashWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CWnd::OnCreate(lpCreateStruct) == -1)
return-1;
// TODO: Add your specialized creation code here
CenterWindow();
SetTimer(1,3000,NULL);
return0;
}
voidCSplashWnd::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Addyour message handler code here and/or call default
if(nIDEvent == 1)
{
HideSplashScreen();
}
/*CWnd::OnTimer(nIDEvent);*/
}
voidCSplashWnd::OnPaint()
{
CPaintDC dc(this);// device context for painting
// TODO: Addyour message handler code here
// Do notcall CWnd::OnPaint() for painting messages
CDC dcImg;
if ( !dcImg.CreateCompatibleDC(&dc))
{
return;
}
BITMAP bm;
m_bitmap.GetBitmap(&bm);
// paint theimage
CBitmap* pOldBit =dcImg.SelectObject(&m_bitmap);
dc.BitBlt(0,0,bm.bmWidth,bm.bmHeight,&dcImg,0,0,SRCCOPY);
dcImg.SelectObject(pOldBit);
}
BOOLCSplashWnd::Create(CWnd* pParentWnd)
{
if ( !m_bitmap.LoadBitmap(IDB_SPLASH))
{
returnFALSE;
}
BITMAP bm;
m_bitmap.GetBitmap(&bm);
returnCreateEx(0,
AfxRegisterWndClass(0,AfxGetApp()->LoadStandardCursor(IDC_ARROW)),
NULL,
WS_POPUP|WS_VISIBLE,
0,
0,
bm.bmWidth,
bm.bmHeight,
pParentWnd->GetSafeHwnd(),
NULL);
}
void CSplashWnd::HideSplashScreen(void)
{
DestroyWindow();
AfxGetMainWnd()->UpdateWindow();
}
三、 在SDI或者MDI中使用CSplashWnd类
(1) 在CWinApp::InitInstance()中调用CSplashWnd::EnableSplashScreen()设置c_bShowSplashWnd;
在PreTranslateMessage()中调用CSplashWnd::PreTranslateAppMessage(),将键盘和鼠标消息传递给CSplashWnd对象
(2) (2)在CMainFrame对象的OnCreate()中调用CSplashWnd::ShowSplashScreen()创建一个静态的SplashScreen窗口对象c_pSplashWnd,并设置其父窗口为CMainFrame.
代码如下:
BOOLCDrawApp::InitInstance()
{
//用来处理是否显示SplashScreen
{
CCommandLineInfo cmdinfo;
ProcessShellCommand(cmdinfo);
CSplashWnd::EnableSplashScreen(cmdinfo.m_bShowSplash);
}
………..
}
BOOLCDrawApp::PreTranslateMessage(MSG* pMsg)
{
if(CSplashWnd::PreTranslateAppMessage(pMsg))
returnTRUE;
returnCWinAppEx::PreTranslateMessage(pMsg);
}
intCMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
return-1;
………..
CSplashWnd::ShowSplashScreen(this);
return0;
}
在此过程中不会出现什么错误,但编译时会提示:IDB_SPLASH没有定义。这需要在资源中加入个位图资源,并将”resource.h” 头文件包含到CSlashWnd.cpp文件中。
四、 在对话框中使用CSplashWnd类
在对话框中使用和在SDI或MDI中使用基本相似,首先在CWinApp的继承类中处理InitInstance()和PreTranslateMessage(MSG* pMsg)两个消息函数,然后在对话框类的WM_CREATE响应函数中显示SplashScreen。
BOOLCDLGApp::InitInstance()
{
//用来处理是否显示SplashScreen
{
CCommandLineInfo cmdinfo;
ProcessShellCommand(cmdinfo);
CSplashWnd::EnableSplashScreen(cmdinfo.m_bShowSplash);
}
……….
}
BOOLCDLGApp::PreTranslateMessage(MSG* pMsg)
{
if (CSplashWnd::PreTranslateAppMessage(pMsg) )
{
returnTRUE;
}
returnCWinApp::PreTranslateMessage(pMsg);
}
intCDLGDlg::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CDialogEx::OnCreate(lpCreateStruct) == -1)
return-1;
// TODO: Add your specialized creation code here
CSplashWnd::ShowSplashScreen(this);
return0;
}