www.pudn.com > L14.zip > MfcSaver.cpp


// MfcSaver.cpp : Defines the class behaviors for the application. 
// 
 
#include "StdAfx.h" 
 
#include "MfcSaver.h" 
#include "MfcSaverDlg.h" 
 
#ifdef _DEBUG 
#define new DEBUG_NEW 
#undef THIS_FILE 
static char THIS_FILE[] = __FILE__; 
#endif 
 
///////////////////////////////////////////////////////////////////////////// 
 
// 
// The screen saver controls a number of icon graphics that bounce around 
// on a black background.  Set some basic defaults and initialize the random 
// number generator with srand().  Later, our RestoreOptions() will be called 
// to recall earlier option settings. 
// 
 
BEGIN_MESSAGE_MAP(CMfcSaver, CScreenSaverWnd) 
	//{{AFX_MSG_MAP(CMfcSaver) 
	ON_WM_TIMER() 
	//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
// As required of CScreenSaverWnd-based screen savers, these are the two 
// global instances of screen saver objects.  One is the saver itself, 
// and one is the dialog for configuring the options of the screen saver. 
// 
// Unlike most MFC applications, there is no instance of any CWinApp object. 
// 
CMfcSaver theSaver; 
CMfcSaverDlg theSaverDialog; 
 
CMfcSaver::CMfcSaver() 
{ 
	m_nIcons = 6; 
	m_nSpeed = 100; 
	srand(time(NULL)); 
} 
 
CMfcSaver::~CMfcSaver() 
{ 
} 
 
///////////////////////////////////////////////////////////////////////////// 
 
// 
// The CMfcSaverDlg will need to be able to access our customizable 
// attributes.  We call OnInitialUpdate() again to reorganize internally if 
// any of these change. 
// 
// The options need to be saved and restored between runs. 
// Probably the biggest thing you might miss from having no CWinApp object 
// will be CWinApp::WriteProfileInt() which saves things to the registry 
// without complicated registry code. 
// 
// For simplicity, we just create an mfcsaver.ini file with the options. 
// 
 
int CMfcSaver::GetIconCount() const 
{ 
	return m_nIcons; 
} 
 
void CMfcSaver::SetIconCount(int nIcons) 
{ 
	m_nIcons = nIcons; 
	OnInitialUpdate(); 
} 
 
int CMfcSaver::GetIconSpeed() const 
{ 
	return m_nSpeed; 
} 
 
void CMfcSaver::SetIconSpeed(int nSpeed) 
{ 
	m_nSpeed = nSpeed; 
	OnInitialUpdate(); 
} 
 
void CMfcSaver::SaveOptions() 
{ 
	CString s; 
	s.Format("%d", GetIconCount()); 
	::WritePrivateProfileString( 
		"MfcSaver", "Count", s, "mfcsaver.ini"); 
	s.Format("%d", GetIconSpeed()); 
	::WritePrivateProfileString( 
		"MfcSaver", "Speed", s, "mfcsaver.ini"); 
} 
 
void CMfcSaver::RestoreOptions() 
{ 
	SetIconCount(::GetPrivateProfileInt( 
		"MfcSaver", "Count", 8, "mfcsaver.ini")); 
	SetIconSpeed(::GetPrivateProfileInt( 
		"MfcSaver", "Speed", 8, "mfcsaver.ini")); 
} 
 
///////////////////////////////////////////////////////////////////////////// 
 
// 
// While this is just demonstrating how to override the virtual functions of 
// CScreenSaverWnd, it also shows something about using CImageList to 
// draw from a library of simple images. 
// 
// When our timer goes off, we just invalidate the window.  The OnDraw() 
// override will be called appropriately when the system has some free cycles 
// to spend on drawing.  Remember:  a screen saver should share the CPU, so 
// the computer can work on other tasks like downloading or numbercrunching. 
// 
 
void CMfcSaver::OnInitialUpdate() 
{ 
	if (!m_hWnd) 
		return; 
 
	// Flush all the icons we have, if any. 
	m_aIcon.RemoveAll(); 
	if (m_ilIcons.m_hImageList) 
		m_ilIcons.DeleteImageList(); 
 
	// Set up for the desired number of icons. 
	m_aIcon.SetSize(m_nIcons); 
	m_ilIcons.Create(IDB_ICONS, 32, 0, RGB(128, 0, 128)); 
 
	int i; 
	for (i = 0; i < m_nIcons; i++) 
		SetupMfcSaverIcon(i); 
 
	m_nSpeed = max(1, m_nSpeed); 
	SetTimer(1, 2000 / m_nSpeed, NULL); 
} 
 
void CMfcSaver::OnDraw(CDC* pDC) 
{ 
	int i; 
	for (i = 0; i < m_nIcons; i++) 
	{ 
		EraseMfcSaverIcon(i, pDC); 
		UpdateMfcSaverIconPosition(i); 
		if (IsMfcSaverIconOffscreen(i)) 
			SetupMfcSaverIcon(i); 
		DrawMfcSaverIcon(i, pDC); 
	} 
} 
 
void CMfcSaver::EraseMfcSaverIcon(int i, CDC* pDC) 
{ 
	CRect rcIcon = CRect(m_aIcon[i].ptP, CSize(32, 32)); 
	pDC->FillSolidRect(&rcIcon, RGB(0, 0, 0)); 
} 
 
void CMfcSaver::DrawMfcSaverIcon(int i, CDC* pDC) 
{ 
	m_ilIcons.Draw(pDC, m_aIcon[i].iImage, m_aIcon[i].ptP, ILD_NORMAL); 
} 
 
void CMfcSaver::OnTimer(UINT nIDEvent)  
{ 
	CScreenSaverWnd::OnTimer(nIDEvent); 
 
	Invalidate(FALSE); 
} 
///////////////////////////////////////////////////////////////////////////// 
 
// 
// Compute the movement of these little square icons. 
// They move until they fall offscreen, then are reinitialized randomly. 
// If they would collide on any move, they don't move but they change 
// direction instead.  If they seem hopelessly stuck, they are recycled. 
// 
// With a bit more work, you could make these icons pass over each other 
// smoothly, or you could double-buffer them to draw with less flicker. 
// 
 
BOOL CMfcSaver::IsMfcSaverIconColliding(int i, CPoint ptP) 
{ 
	CRect rcI = CRect(ptP, CSize(32, 32)); 
 
	int j; 
	for (j = 0; j < m_nIcons; j++) 
	{ 
		if (j == i) 
			continue; 
 
		CRect rcJ = CRect(m_aIcon[j].ptP, CSize(32, 32)); 
		if (rcJ.IntersectRect(&rcJ, &rcI)) 
			return TRUE; 
	} 
 
	return FALSE; 
} 
 
BOOL CMfcSaver::IsMfcSaverIconOffscreen(int i) 
{ 
	CRect rcI = CRect(m_aIcon[i].ptP, CSize(32, 32)); 
	CRect rcC; 
	GetClientRect(&rcC); 
 
	return !rcC.IntersectRect(&rcC, &rcI); 
} 
 
void CMfcSaver::UpdateMfcSaverIconPosition(int i) 
{ 
	CPoint ptP; 
 
	ptP = m_aIcon[i].ptP + m_aIcon[i].szV; 
	if (IsMfcSaverIconColliding(i, ptP)) 
	{ 
		m_aIcon[i].nStuck++; 
		BounceMfcSaverIcon(i); 
		if (m_aIcon[i].nStuck > 5) 
			SetupMfcSaverIcon(i); 
		return; 
	} 
 
	m_aIcon[i].nStuck = 0; 
	m_aIcon[i].ptP = ptP; 
} 
 
void CMfcSaver::BounceMfcSaverIcon(int i) 
{ 
	do 
	{ 
		m_aIcon[i].szV.cx = (rand() % 5) - 2; 
		m_aIcon[i].szV.cy = (rand() % 5) - 2; 
	} while (m_aIcon[i].szV.cx == 0 && m_aIcon[i].szV.cy == 0); 
} 
 
void CMfcSaver::SetupMfcSaverIcon(int i) 
{ 
	int count = max(1, m_ilIcons.GetImageCount()); 
 
	int breakout = 10; 
	do 
	{ 
		m_aIcon[i].iImage = (rand() % count); 
		m_aIcon[i].ptP.x = 
			(rand() % ::GetSystemMetrics(SM_CXSCREEN)); 
		m_aIcon[i].ptP.y = 
			(rand() % ::GetSystemMetrics(SM_CXSCREEN)); 
		BounceMfcSaverIcon(i); 
		m_aIcon[i].nStuck = 0; 
 
	} while (breakout > 0 && 
	         IsMfcSaverIconColliding(i, m_aIcon[i].ptP)); 
}