七巧板是我国民间流传的一种拼图游戏,制作简单但变化多端,具有很高的益智价值。七巧板制作非常简单,使用一张正方形的厚纸板按图13-6所示图样裁开即可。本程序在计算机上模拟使用七巧板进行拼图。
CRgn类用来表示一个区域,其形状不限于矩形。
CRgn类有许多成员函数,其中较重要的有:
1.建立区域:
BOOL CreateRectRgn( int x1, int y1, int x2, int y2 );
BOOL CreateRectRgnIndirect( LPCRECT lpRect );
BOOL CreateEllipticRgn( int x1, int y1, int x2, int y2 );
BOOL CreateEllipticRgnIndirect( LPCRECT lpRect );
BOOL CreatePolygonRgn( LPPOINT lpPoints, int nCount, int nMode );
这几个成员函数分别用于建立矩形、椭圆和多边形区域。对于矩形和椭圆区域要求给出矩形(或椭圆的包含矩形)的参数;对多边形区域,除要求给出多边形的各顶点坐标和顶点个数外,还应说明多边形区域的填充方式。参数nMode可选ALTERNATE 或 WINDING值。如果建立区域成功,返回非零值,否则返回零。
2.取区域的包含矩形
int GetRgnBox ( LPRECT lpRect ) const;
3.移动区域
int OffsetRgn( int x, int y );
int OffsetRgn( POINT point );
该函数可移动一个区域,参数x,y或point为偏移量。
4.测试给定坐标点是否在区域中
BOOL PtInRegion( int x, int y ) const;
BOOL PtInRegion( POINT point ) const;
该函数用来测试一给定坐标点是否在区域中。若在,则返回非零值,否则返回零。
5.测试给定矩形是否在区域中
BOOL RectInRegion( LPCRECT lpRect ) const;
程序:
// Example 13-7: 七巧板程序 //
#include <afxwin.h>
#include <afxext.h>
// 拼板类
#define MAX_POINTS 4
#define CHIP_WIDTH 240
#define DELTA 30
class CChip : public CObject
{
DECLARE_SERIAL(CChip)
int m_nType;
CPoint m_pointList[MAX_POINTS];
int m_nPointCount;
public:
CChip(){}
void SetChip(int type, POINT *ppointlist, int count);
void DrawChip(CDC *pDC);
BOOL PtInChip(POINT point);
LPCRECT GetRect();
void MoveTo(CSize offset);
void Rotation();
void Serialize(CArchive &ar);
};
IMPLEMENT_SERIAL(CChip, CObject, 1)
// 设置拼图块参数
void CChip::SetChip(int type, POINT *ppointlist, int count)
{
m_nType = type;
m_nPointCount = count;
for(int i=0; i<count; i++)
m_pointList[i] = ppointlist[i];
}
// 绘出拼图块
void CChip::DrawChip(CDC *pDC)
{
CPen penNew, *ppenOld;
CBrush brushNew, *pbrushOld;
switch(m_nType)
{
case 1:
brushNew.CreateSolidBrush(RGB(127, 127, 127));
break;
case 2:
brushNew.CreateSolidBrush(RGB(255, 0, 0));
break;
case 3:
brushNew.CreateSolidBrush(RGB(0, 255, 0));
break;
case 4:
brushNew.CreateSolidBrush(RGB(0, 0, 255));
break;
case 5:
brushNew.CreateSolidBrush(RGB(127, 127, 0));
break;
case 6:
brushNew.CreateSolidBrush(RGB(127, 0, 127));
break;
case 7:
brushNew.CreateSolidBrush(RGB(0, 127, 127));
break;
}
penNew.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
ppenOld = pDC->SelectObject(&penNew);
pbrushOld = pDC->SelectObject(&brushNew);
pDC->Polygon(m_pointList, m_nPointCount);
pDC->SelectObject(ppenOld);
pDC->SelectObject(pbrushOld);
}
// 检测一点是否在拼图块中
BOOL CChip::PtInChip(POINT point)
{
CRgn rgn;
rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);
return rgn.PtInRegion(point);
}
// 取拼图块的包含矩形
LPCRECT CChip::GetRect()
{
static RECT rect;
CRgn rgn;
rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);
rgn.GetRgnBox(&rect);
rect.right++;
rect.bottom++;
return ▭
}
// 旋转拼图块
void CChip::Rotation()
{
CRect rect;
CRgn rgn;
rgn.CreatePolygonRgn(m_pointList, m_nPointCount, 0);
rgn.GetRgnBox(&rect);
double x = rect.left+rect.Width()/2; // 计算旋转中心
double y = rect.top+rect.Height()/2;
double dx, dy;
for(int i=0; i<m_nPointCount; i++) // 旋转各点
{
dx = m_pointList[i].x-x;
dy = m_pointList[i].y-y;
m_pointList[i].x = (int)(x+dx*0.7071-dy*0.7071);
m_pointList[i].y = (int)(y+dx*0.7071+dy*0.7071);
}
}
// 移动拼图块
void CChip::MoveTo(CSize offset)
{
for(int i=0; i<m_nPointCount; i++)
m_pointList[i] = m_pointList[i]+offset;
}
// 序列化
void CChip::Serialize(CArchive &ar)
{
if(ar.IsStoring())
{
ar << m_nType;
ar << m_nPointCount;
for(int i=0; i<m_nPointCount; i++)
ar << m_pointList[i];
}
else
{
ar >> m_nType;
ar >> m_nPointCount;
for(int i=0; i<m_nPointCount; i++)
ar >> m_pointList[i];
}
}
// 文档类
#define CHIP_COUNT 7
class CMyDoc : public CDocument
{
DECLARE_DYNCREATE(CMyDoc)
CChip m_chipList[CHIP_COUNT];
public:
void Reset();
virtual void DeleteContents();
virtual void Serialize(CArchive& ar);
};
IMPLEMENT_DYNCREATE(CMyDoc, CDocument)
// 初始化拼图块
void CMyDoc::Reset()
{
POINT pointList[MAX_POINTS];
pointList[0].x = DELTA;
pointList[0].y = DELTA;
pointList[1].x = DELTA+CHIP_WIDTH;
pointList[1].y = DELTA;
pointList[2].x = DELTA+CHIP_WIDTH/2;
pointList[2].y = DELTA+CHIP_WIDTH/2;
m_chipList[0].SetChip(1, pointList, 3);
pointList[0].x = DELTA;
pointList[0].y = DELTA;
pointList[1].x = DELTA;
pointList[1].y = DELTA+CHIP_WIDTH;
pointList[2].x = DELTA+CHIP_WIDTH/2;
pointList[2].y = DELTA+CHIP_WIDTH/2;
m_chipList[1].SetChip(2, pointList, 3);
pointList[0].x = DELTA+CHIP_WIDTH;
pointList[0].y = DELTA;
pointList[1].x = DELTA+CHIP_WIDTH;
pointList[1].y = DELTA+CHIP_WIDTH/2;
pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].y = DELTA+CHIP_WIDTH/4;
m_chipList[2].SetChip(3, pointList, 3);
pointList[0].x = DELTA+CHIP_WIDTH/2;
pointList[0].y = DELTA+CHIP_WIDTH/2;
pointList[1].x = DELTA+CHIP_WIDTH/4;
pointList[1].y = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].y = DELTA+(CHIP_WIDTH*3)/4;
m_chipList[3].SetChip(4, pointList, 3);
pointList[0].x = DELTA+CHIP_WIDTH;
pointList[0].y = DELTA+CHIP_WIDTH/2;
pointList[1].x = DELTA+CHIP_WIDTH;
pointList[1].y = DELTA+CHIP_WIDTH;
pointList[2].x = DELTA+CHIP_WIDTH/2;
pointList[2].y = DELTA+CHIP_WIDTH;
m_chipList[4].SetChip(5, pointList, 3);
pointList[0].x = DELTA+(CHIP_WIDTH*3)/4;
pointList[0].y = DELTA+CHIP_WIDTH/4;
pointList[1].x = DELTA+CHIP_WIDTH/2;
pointList[1].y = DELTA+CHIP_WIDTH/2;
pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].y = DELTA+(CHIP_WIDTH*3)/4;
pointList[3].x = DELTA+CHIP_WIDTH;
pointList[3].y = DELTA+CHIP_WIDTH/2;
m_chipList[5].SetChip(6, pointList, 4);
pointList[0].x = DELTA;
pointList[0].y = DELTA+CHIP_WIDTH;
pointList[1].x = DELTA+CHIP_WIDTH/4;
pointList[1].y = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].x = DELTA+(CHIP_WIDTH*3)/4;
pointList[2].y = DELTA+(CHIP_WIDTH*3)/4;
pointList[3].x = DELTA+CHIP_WIDTH/2;
pointList[3].y = DELTA+CHIP_WIDTH;
m_chipList[6].SetChip(7, pointList, 4);
}
// 清理文档:关闭文档、建立新文档和打开文档前调用
void CMyDoc::DeleteContents()
{
Reset();
CDocument::DeleteContents();
}
// 系列化:读写文档时自动调用
void CMyDoc::Serialize(CArchive &ar)
{
for(int i=0; i<CHIP_COUNT; i++)
m_chipList[i].Serialize(ar);
}
// 视图类 ///
class CMyView : public CView
{
DECLARE_DYNCREATE(CMyView)
BOOL m_bCaptured;
CPoint m_pointMouse;
int m_nCurrIndex;
public:
CMyView(){m_bCaptured = FALSE;}
CMyDoc* GetDocument(){return (CMyDoc*)m_pDocument;}
virtual void OnInitialUpdate();
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnDraw(CDC* pDC);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
DECLARE_MESSAGE_MAP()
};
IMPLEMENT_DYNCREATE(CMyView, CView)
BEGIN_MESSAGE_MAP(CMyView, CView)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_WM_RBUTTONDOWN()
ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
END_MESSAGE_MAP()
// 更新初始化:当建立新文档或打开文档时调用
void CMyView::OnInitialUpdate()
{
CView::OnInitialUpdate();
Invalidate();
}
// 绘制视图:程序开始运行或窗体发生变化时自动调用
void CMyView::OnDraw(CDC* pDC)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
for(int i=0; i<CHIP_COUNT; i++)
pDoc->m_chipList[i].DrawChip(pDC);
}
// 消息响应:用户点击鼠标左键时调用
void CMyView::OnLButtonDown(UINT nFlags, CPoint point)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
for(int i=CHIP_COUNT-1; i>=0; i--)
if(pDoc->m_chipList[i].PtInChip(point))
{
SetCapture();
m_bCaptured = TRUE;
m_pointMouse = point;
m_nCurrIndex = i;
break;
}
}
// 释放鼠标左键
void CMyView::OnLButtonUp(UINT nFlags, CPoint point)
{
if(m_bCaptured)
{
::ReleaseCapture();
m_bCaptured = FALSE;
}
}
// 移动鼠标左键
void CMyView::OnMouseMove(UINT nFlags, CPoint point)
{
if(m_bCaptured)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
InvalidateRect(pDoc->m_chipList[m_nCurrIndex].GetRect());
CSize offset(point-m_pointMouse);
pDoc->m_chipList[m_nCurrIndex].MoveTo(offset);
InvalidateRect(pDoc->m_chipList[m_nCurrIndex].GetRect());
m_pointMouse = point;
pDoc->SetModifiedFlag();
}
}
// 按下鼠标右键: 旋转拼图块
void CMyView::OnRButtonDown(UINT nFlags, CPoint point)
{
CMyDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
for(int i=CHIP_COUNT-1; i>=0; i--)
if(pDoc->m_chipList[i].PtInChip(point))
{
InvalidateRect(pDoc->m_chipList[i].GetRect());
pDoc->m_chipList[i].Rotation();
InvalidateRect(pDoc->m_chipList[i].GetRect(), FALSE);
pDoc->SetModifiedFlag();
break;
}
}
// 准备打印:设置打印参数
BOOL CMyView::OnPreparePrinting(CPrintInfo* pInfo)
{
pInfo->SetMaxPage(1);
return DoPreparePrinting(pInfo);
}
// 主框架类 //
class CMainFrame : public CFrameWnd
{
DECLARE_DYNCREATE(CMainFrame)
};
IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
// 应用程序类 ///
#define IDR_MAINFRAME 128 // 主框架的资源代号
class CMyApp : public CWinApp
{
public:
virtual BOOL InitInstance();
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()
// 初始化程序实例:建立并登记文档模板
BOOL CMyApp::InitInstance()
{
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
CCommandLineInfo cmdInfo;
ParseCommandLine(cmdInfo);
if (!ProcessShellCommand(cmdInfo))
return FALSE;
m_pMainWnd->ShowWindow(SW_SHOWMAXIMIZED);
return TRUE;
}
// 全局应用程序对象
CMyApp theApp;