钻石图的实验原理:
双缓冲技术:
双缓冲是一种基本的动画技术,主要用于解决单缓冲擦除图像时带来的屏幕闪烁问题。
所谓双缓冲,是指一个屏幕设备上下文(屏幕缓冲区)和一个内存设备上下文(内存缓冲区)。内存缓冲区用于准备图形,屏幕缓冲区用于显示图形。图形绘制到内存缓冲区,而非直接绘制到屏幕缓冲区。每帧动画只执行图形从内存缓冲区到屏幕缓冲区的拷贝操作,屏幕缓冲区只是内存缓冲区的一个映像。双缓冲机制中根本不需要擦除屏幕缓冲区,因此有效地避免了屏幕闪烁现象,可生成平滑的逐帧动画。
实验效果图:
在绘制旋转的钻石图时,首先定义金刚石图案类,绘制出静态的钻石图,然后定义定时器消息响应函数,让旋转角每次增加,重新绘制钻石图,利用双缓冲技术即可将旋转的钻石图绘制出来。
核心代码如下
// CppDiamondView.cpp : implementation of the CCppDiamondView class
//
#include "stdafx.h"
#include "CppDiamond.h"
#include "CppDiamondDoc.h"
#include "CppDiamondView.h"
#include "Diamond.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CCppDiamondView
IMPLEMENT_DYNCREATE(CCppDiamondView, CView)
BEGIN_MESSAGE_MAP(CCppDiamondView, CView)
//{{AFX_MSG_MAP(CCppDiamondView)
ON_WM_TIMER()
//}}AFX_MSG_MAP
// Standard printing commands
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()
/
// CCppDiamondView construction/destruction
CCppDiamondView::CCppDiamondView()
{
// TODO: add construction code here
Alpha = 0; //初始旋转角
ptr = new CDiamond; //动态建立金刚石图案对象
}
CCppDiamondView::~CCppDiamondView()
{
delete ptr; //释放动态创建的金刚石图案的内存空间
ptr = NULL; //置指针为空
}
BOOL CCppDiamondView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/
// CCppDiamondView drawing
void CCppDiamondView::OnDraw(CDC* pDC)
{
CCppDiamondDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
SetTimer(1,100,NULL); //设置定时器
DoubleBuffer(pDC); //调用双缓冲函数绘制金刚石图案
}
/
// CCppDiamondView printing
BOOL CCppDiamondView::OnPreparePrinting(CPrintInfo* pInfo)
{
// default preparation
return DoPreparePrinting(pInfo);
}
void CCppDiamondView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add extra initialization before printing
}
void CCppDiamondView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
// TODO: add cleanup after printing
}
/
// CCppDiamondView diagnostics
#ifdef _DEBUG
void CCppDiamondView::AssertValid() const
{
CView::AssertValid();
}
void CCppDiamondView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CCppDiamondDoc* CCppDiamondView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CCppDiamondDoc)));
return (CCppDiamondDoc*)m_pDocument;
}
#endif //_DEBUG
/
// CCppDiamondView message handlers
void CCppDiamondView::DoubleBuffer(CDC* pDC)
{
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
CDC memDC; //声明内存缓冲区
memDC.CreateCompatibleDC(pDC); //创建与pDC兼容的memDC
CBitmap NewBitmap, *pOldBitmap; //声明位图对象和指针
NewBitmap.CreateCompatibleBitmap(pDC,rect.Width(),rect.Height()); //创建兼容的位图
pOldBitmap = memDC.SelectObject(&NewBitmap); //将位图选入内存
memDC.FillSolidRect(rect,pDC->GetBkColor()); //用背景色填充客户区
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
memDC.SetMapMode(MM_ANISOTROPIC); //定义内存的坐标系
memDC.SetWindowExt(rect.Width(),rect.Height());
memDC.SetViewportExt(rect.Width(),-rect.Height());
memDC.OffsetViewportOrg(rect.Width()/2,rect.Height()/2);
DrawGraph(&memDC); //向内存绘制图形
pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&memDC,-rect.Width()/2,-rect.Height()/2,SRCCOPY); //将memDC中的位图拷贝到pDC
memDC.SelectObject(pOldBitmap);
NewBitmap.DeleteObject();
memDC.DeleteDC();
}
void CCppDiamondView::DrawGraph(CDC* pDC)
{
ptr->SetAngle(Alpha); //设置金刚石图案的旋转角
ptr->Draw(pDC); //根据旋转角绘制金刚石图案板
}
void CCppDiamondView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
Alpha += 1; //角度增量
if (Alpha == 360) //循环播放
{
Alpha = 0;
}
Invalidate(false); //使客户区无效,强制执行OnDraw函数进行重绘
CView::OnTimer(nIDEvent);
}
完整代码可添加QQ获取
1173953942 备注钻石图即可