⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 checkerctrl.cpp

📁 操作系统实验演示代码(三个实验
💻 CPP
字号:
//Author:			Mehdi Mousavi
//Data of release:	8th of September, 2000
//Email:			Webmaster@modemmania.com

// CheckerCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "CheckerCtrl.h"
#include "Resource.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CCheckerCtrl

#define BLANKED_BLOCKS_COLOR	RGB(252, 252, 252)

CCheckerCtrl::CCheckerCtrl()
{
	//Sets the background brush of the client area
	m_backgroundBrush.CreateSolidBrush(GetSysColor(COLOR_WINDOW));
	
	//Resets m_nyPos for scrolling purposes
	m_nyPos = 0;

	//Resets m_nBlockStartPos so that when the WM_PAINT message
	//is triggered, the control starts to show blocks
	//from m_nBlockStartPos position
	m_nBlockStartPos = 0;

	//Sets the starting index of blocks
	m_nStartIndex = 0;

	//Total number of blocks
	m_nNumberofBlocks = 0;

	//Offset for scrolling purposes
	m_nOffset = 0;

	m_nTotalVisibleBlocks = 0;

	m_nBlocksPerRow = 0;
}

CCheckerCtrl::~CCheckerCtrl()
{
}

BOOL CCheckerCtrl::Create(DWORD dwStyle, const RECT &rect, CWnd *pParentWnd, UINT nID)
{
	//Postcondition:
	//	Creates a window after being registered, as well as
	//	setting all the required variables used hereinafter.
	static CString className = AfxRegisterWndClass(CS_HREDRAW | CS_VREDRAW);
	BOOL bRet = CWnd::CreateEx(WS_EX_CLIENTEDGE, 
								className,
								NULL,
								dwStyle,
								rect.left,
								rect.top,
								rect.right - rect.left,
								rect.bottom - rect.top,
								pParentWnd->GetSafeHwnd(),
								(HMENU) nID);

	m_nID = nID;
	m_pParentWnd = pParentWnd;
	
	SetCursor(LoadCursor(NULL, IDC_ARROW));
	
	return bRet;
}


BEGIN_MESSAGE_MAP(CCheckerCtrl, CWnd)
	//{{AFX_MSG_MAP(CCheckerCtrl)
	ON_WM_PAINT()
	ON_WM_VSCROLL()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_RBUTTONDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CCheckerCtrl message handlers

void CCheckerCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here

	//Fill the background color of the client area
	dc.FillRect(m_rcClient, &m_backgroundBrush);

	UINT nColumn = 0, nRow = 0;
	
	//Calculate the index of the last visible block
	//within the client area
	UINT nBlockEndPos = m_nBlockStartPos + m_nTotalVisibleBlocks + m_nBlocksPerRow;
	if(nBlockEndPos > m_nNumberofBlocks)
		nBlockEndPos = m_nNumberofBlocks;

	for(UINT i = m_nBlockStartPos; i < nBlockEndPos; i++)
	{
		CBrush brush(m_crColor.GetAt(i));
		SetBlock(nRow, nColumn, brush, dc);
		if((i + 1 - m_nBlockStartPos) % m_nBlocksPerRow == 0)
		{
			nRow++;
			nColumn = 0;
		}
		else
			nColumn++;
	}
}

void CCheckerCtrl::SetTotalBlocks(const UINT nNumberofBlocks, const UINT nStartIndex)
{
	//Postcondition:
	//	Sets the member variable m_nNumberofBlocks to the specified
	//	number of blocks. Then creates an array of COLORREF, sized
	//	nNumberofBlocks, and initialize it with white color.
	//	Thereafter, it computes m_nOffset for scrolling purposes.
	m_nNumberofBlocks = nNumberofBlocks;

	m_crColor.SetSize(m_nNumberofBlocks);
	for(UINT i = 0; i < m_nNumberofBlocks; i++)
		m_crColor.SetAt(i, BLANKED_BLOCKS_COLOR);

	GetClientRect(m_rcClient);
	m_nBlocksPerRow = m_rcClient.Width() / 9;
	m_nBlocksPerColumn = m_rcClient.Height() / 11;
	
	m_nTotalVisibleBlocks = m_nBlocksPerRow * m_nBlocksPerColumn;
	
	//Calculate the vertical scroll bar's range
	int nOffset = (m_nNumberofBlocks / m_nBlocksPerRow);
	if(m_nNumberofBlocks % m_nBlocksPerRow != 0)
		nOffset++;
	
	m_nOffset = nOffset - m_nBlocksPerColumn;
	if(m_nOffset > 0)
		SetScrollRange(SB_VERT, 0, m_nOffset);

	//	Sets the starting index of blocks
	m_nStartIndex = nStartIndex;
}

void CCheckerCtrl::SetBlock(int nRow, int nColumn, CBrush &brush, CDC &dc)
{
	//Postcondition:
	//	Places a block on nRow, nColumn ordered pair, 
	//	and paints it with brush color
	CRect rect = GetRect(nRow, nColumn);

	dc.Rectangle(&rect);
	
	rect.left++;
	rect.top++;
	rect.bottom--;
	rect.right--;
	
	dc.FillRect(rect, &brush);
}

void CCheckerCtrl::SetBlock(const UINT nBlockNumber, const COLORREF crColor)
{
	//Postcondition:
	//	Sets the color of a specified block number to crColor
	ASSERT(nBlockNumber - m_nStartIndex < m_nNumberofBlocks);
	m_crColor.SetAt(nBlockNumber - m_nStartIndex, crColor);
}

void CCheckerCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	// TODO: Add your message handler code here and/or call default

	int nyOffset;
	switch(nSBCode)
	{
	case SB_PAGEDOWN:
		if(m_nyPos < m_nOffset)
		{
			if(m_nyPos + 2 < m_nOffset)
				nyOffset = 2;
			else
				nyOffset = m_nOffset - m_nyPos;

			m_nyPos += nyOffset;
			m_nBlockStartPos += m_nBlocksPerRow * nyOffset;

			SetScrollPos(SB_VERT, m_nyPos);
			ScrollWindow(0, -nyOffset * 11);
		}
		break;

	case SB_PAGEUP:
		if(m_nyPos > 0)
		{
			if(m_nyPos - 2 > 0)
				nyOffset = 2;
			else
				nyOffset = m_nyPos;

			m_nBlockStartPos -= m_nBlocksPerRow * nyOffset;

			m_nyPos -= nyOffset;
			SetScrollPos(SB_VERT, m_nyPos);
			ScrollWindow(0, nyOffset * 11);
		}
		break;

	case SB_LINEUP:
		if(m_nyPos > 0)
		{
			m_nBlockStartPos -= m_nBlocksPerRow;

			m_nyPos--;
			SetScrollPos(SB_VERT, m_nyPos);
			ScrollWindow(0, 11);
		}
		break;

	case SB_LINEDOWN:
		if(m_nyPos < m_nOffset)
		{
			m_nBlockStartPos += m_nBlocksPerRow;

			m_nyPos++;
			SetScrollPos(SB_VERT, m_nyPos);
			ScrollWindow(0, -11);
		}
		break;
	}

	CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}

void CCheckerCtrl::Refresh()
{
	//Postcondition:
	//	Refreshes the client area of the control
	Invalidate();
}

COLORREF CCheckerCtrl::GetBlock(const UINT nBlockNumber) const
{
	//Precondition:
	//	nBlockNumber must be in the range of the defined blocks
	//Postcondition:
	//	Takes the color of the specified index
	ASSERT(nBlockNumber >= m_nStartIndex && nBlockNumber - m_nStartIndex <= m_nNumberofBlocks);
	return m_crColor.GetAt(nBlockNumber - m_nStartIndex);
}

void CCheckerCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	SetFocus();

	DWORD dwPos = GetMessagePos();
	CPoint clickedPoint((int)(short)LOWORD(dwPos), (int)(short)HIWORD(dwPos));
	ScreenToClient(&clickedPoint);
	
	if(clickedPoint.x % 9 == 0 || clickedPoint.y % 11 == 0)
		m_bShouldUpdated = FALSE;
	else
	{
		UINT nY = clickedPoint.y / 11;
		UINT nX = clickedPoint.x / 9;

		UINT nIndex = nY * m_nBlocksPerRow + nX + m_nyPos * m_nBlocksPerRow;
		
		if(nIndex < m_nNumberofBlocks && nX < m_nBlocksPerRow)
		{
			SetCapture();

			CString strNumber;
			strNumber.Format("%d", nIndex + m_nStartIndex);
			
			CreateSafeTooltipRect(clickedPoint.x, clickedPoint.y, strNumber);
			
			CClientDC dc(this);
			CBrush brush;
			brush.CreateSolidBrush(GetSysColor(COLOR_INFOBK));
			dc.Rectangle(tooltipRect);
			
			tooltipRect.left++;
			tooltipRect.top++;
			tooltipRect.bottom--;
			tooltipRect.right--;
			
			dc.FillRect(tooltipRect, &brush);
			
			CFont font;
			LOGFONT logFont;
			strcpy(logFont.lfFaceName, "Verdana");
			logFont.lfHeight = -MulDiv(12, GetDeviceCaps(dc.m_hDC, LOGPIXELSY), 72);
			logFont.lfWidth = 0;
			logFont.lfEscapement = 0;
			logFont.lfItalic = FALSE;
			logFont.lfStrikeOut = FALSE;
			logFont.lfUnderline = FALSE;
			logFont.lfWeight = FW_BOLD;
			
			font.CreateFontIndirect(&logFont);
			
			dc.SelectObject(font);
			
			dc.SetTextColor(GetSysColor(COLOR_INFOTEXT));
			dc.SetBkColor(GetSysColor(COLOR_INFOBK));
			dc.DrawText(strNumber, tooltipRect, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
			
			tooltipRect.left--;
			tooltipRect.top--;
			tooltipRect.bottom++;
			tooltipRect.right++;

			m_bShouldUpdated = TRUE;
		}
	}

	CWnd::OnLButtonDown(nFlags, point);
}

void CCheckerCtrl::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_bShouldUpdated)
	{
		CClientDC dc(this);
		InvalidateRect(&tooltipRect, FALSE);
		ReleaseCapture();
		
		m_bShouldUpdated = FALSE;
	}

	CWnd::OnLButtonUp(nFlags, point);
}

void CCheckerCtrl::CreateSafeTooltipRect(int x, int y, LPCTSTR lpszText)
{
	int nTextLength = strlen(lpszText);
	int nTextWidth = nTextLength;
	if(nTextWidth < 5)
		nTextWidth = 5;
	
	if(x + 12 * nTextWidth <= m_rcClient.right)
		tooltipRect.right = x + 12 * nTextWidth;
	else
		tooltipRect.right = x - 12 * nTextWidth;

	if(y + 25 <= m_rcClient.bottom)
		tooltipRect.bottom = y + 25;
	else
		tooltipRect.bottom = y - 25;

	tooltipRect.left = x;
	tooltipRect.top = y;

	if(tooltipRect.left > tooltipRect.right)
	{
		int nTemp = tooltipRect.left;
		tooltipRect.left = tooltipRect.right;
		tooltipRect.right = nTemp;
	}

	if(tooltipRect.top > tooltipRect.bottom)
	{
		int nTemp = tooltipRect.bottom;
		tooltipRect.bottom = tooltipRect.top;
		tooltipRect.top = nTemp;
	}
}

void CCheckerCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	SetCursor(LoadCursor(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDC_CURSOR_HAND)));
	CWnd::OnMouseMove(nFlags, point);
}

void CCheckerCtrl::Reset()
{
	for(UINT i = 0; i < m_nNumberofBlocks; i++)
		m_crColor.SetAt(i, BLANKED_BLOCKS_COLOR);
}

void CCheckerCtrl::Update(const UINT nBlockNumber)
{
	//Precondition:
	//	nBlockNumber must be in the range of the defined blocks
	//Postcondition:
	//	Updates the color of a specified index on CRT, if and only
	//	if it's already visible
	ASSERT(nBlockNumber >= m_nStartIndex && nBlockNumber - m_nStartIndex <= m_nNumberofBlocks);

	if(IsVisible(nBlockNumber))
	{
		UINT nRow = (nBlockNumber - m_nStartIndex) / m_nBlocksPerRow - m_nyPos;
		UINT nColumn = (nBlockNumber - m_nStartIndex) % m_nBlocksPerRow;
		
		CClientDC dc(this);
		CRect rect = GetRect(nRow, nColumn);
		
		rect.left++;
		rect.top++;
		rect.bottom--;
		rect.right--;
		
		CBrush brush;
		brush.CreateSolidBrush(m_crColor.GetAt(nBlockNumber - m_nStartIndex));
		dc.FillRect(rect, &brush);
	}
}

CRect CCheckerCtrl::GetRect(const UINT nRow, const UINT nColumn)
{
	//Postcondition:
	//	Returns the rectangular area of a specified block
	//	placed in nRow(th) row and nColumn(th) column.
	CRect rect;
	rect.left = nColumn * 9 + 1;
	rect.top = nRow * 11 + 1;
	rect.right = rect.left + 7;
	rect.bottom = rect.top + 9;
	
	return rect;
}

BOOL CCheckerCtrl::IsVisible(const UINT nBlockNumber)
{
	//Calculate the index of the last visible block
	//within the client area
	UINT nBlockEndPos = m_nBlockStartPos + m_nTotalVisibleBlocks + m_nBlocksPerRow;
	if(nBlockEndPos > m_nNumberofBlocks)
		nBlockEndPos = m_nNumberofBlocks;

	if(nBlockNumber >= m_nBlockStartPos && nBlockNumber <= nBlockEndPos)
		return TRUE;
	else
		return FALSE;
}

void CCheckerCtrl::OnRButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	SetFocus();
	if(!(point.x % 9 == 0 || point.y % 11 == 0))
	{
		UINT nY = point.y / 11;
		UINT nX = point.x / 9;

		UINT nIndex = nY * m_nBlocksPerRow + nX + m_nyPos * m_nBlocksPerRow;
		if(nIndex < m_nNumberofBlocks && nX < m_nBlocksPerRow)
			m_pParentWnd->PostMessage(WM_CHECKERCTRL_RBUTTONDOWN, m_nID, nIndex + m_nStartIndex);
	}

	CWnd::OnRButtonDown(nFlags, point);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -