(4)在CDBufferView中添加成员变量:
int m_nDrawTool; //绘图工具选择
int m_nButtonDown; //按钮按下次数
Bitmap* m_pBitmap; //虚拟画布
Graphics* m_pGP; //虚拟画布图像对象指针
CArray<CPoint,CPoint> m_PointList; //记录图形各顶点坐标
(5)在CDBufferView::CDBufferView()中添加初始化代码:
m_nDrawTool=0;
m_nButtonDown=0;
m_pBitmap=NULL;
m_pGP=NULL;
在CDBufferView::OnInitialUpdate()中创建虚拟画布(缓存):
m_pBitmap = new Bitmap(800,600,PixelFormat32bppARGB);//建立800×600的图像
m_pGP=new Graphics(m_pBitmap);//建立图像对象,用于在虚拟画布上绘制图像
m_pGP->Clear(Color::White);//必须有,用背景色填充画布;
在CDBufferView::~CDBufferView()中释放占用的资源:
if(m_pBitmap!=NULL) delete m_pBitmap;
if(m_pGP!=NULL) delete m_pGP;
if(m_PointList.GetCount()>0)m_PointList.RemoveAll();
(6)分别建立直线、矩形、椭圆和曲线的菜单命令方法:
void CDBufferView::OnDrawLine()
{ this->m_nDrawTool=0;} //当前状态设为画直线
void CDBufferView::OnUpdateDrawLine(CCmdUI *pCmdUI)
{ pCmdUI->SetCheck(this->m_nDrawTool==0);}
void CDBufferView::OnDrawRectangle()
{ this->m_nDrawTool=1;} //当前状态设为画矩形
void CDBufferView::OnUpdateDrawRectangle(CCmdUI *pCmdUI)
{ pCmdUI->SetCheck(this->m_nDrawTool==1);}
void CDBufferView::OnDrawEllipse()
{ this->m_nDrawTool=2;} //当前状态设为画椭圆
void CDBufferView::OnUpdateDrawEllipse(CCmdUI *pCmdUI)
{ pCmdUI->SetCheck(this->m_nDrawTool==2); }
void CDBufferView::OnDrawCurve()
{ this->m_nDrawTool=3;}//当前状态设为画曲线
void CDBufferView::OnUpdateDrawCurve(CCmdUI *pCmdUI)
{ pCmdUI->SetCheck(this->m_nDrawTool==3);}
(7)建立鼠标左键按下事件响应函数,并添加如下代码:
void CDBufferView::OnLButtonDown(UINT nFlags, CPoint point)
{ if(m_nDrawTool>=0 && m_nDrawTool<=3)
{
if(m_nButtonDown==0)
{ if(m_PointList.GetCount()>0) m_PointList.RemoveAll();}
m_PointList.Add(point);//记录鼠标单击点
m_nButtonDown++;
}
CView::OnLButtonDown(nFlags, point);
}
(8)建立鼠标移动事件响应函数,并添加如下代码:
void CDBufferView::OnMouseMove(UINT nFlags, CPoint point)
{
Bitmap* tempBitmap=m_pBitmap->Clone(0,0,m_pBitmap->GetWidth(), m_pBitmap->GetHeight(), PixelFormat32bppARGB); //建立虚拟画布副本
Graphics* pgp=new Graphics(tempBitmap);
PointF* tempPoint;
CPoint tempP;
switch(this->m_nDrawTool)
{
case 0:
if(m_nButtonDown>=1)
{
tempPoint=new PointF[2];
tempP=m_PointList.GetAt(0);
tempPoint[0].X=(REAL)tempP.x; tempPoint[0].Y=(REAL)tempP.y;
tempPoint[1].X=(REAL)point.x; tempPoint[1].Y=(REAL)point.y;
Pen pen(Color::Black,1.0f);
pgp->DrawLine(&pen,tempPoint[0],tempPoint[1]);//画布副本上绘制直线
delete[] tempPoint;
}
break;
case 1:
if(m_nButtonDown>=1)
{
tempP=m_PointList.GetAt(0);
Pen pen(Color::Black,1.0f);
REAL tempX=(REAL)min(tempP.x,point.x);
REAL tempY=(REAL)min(tempP.y,point.y);
REAL tempW=(REAL)(tempP.x>point.x?tempP.x-point.x:point.x-tempP.x);
REAL tempH=(REAL)(tempP.y>point.y?tempP.y-point.y:point.y-tempP.y);
pgp->DrawRectangle(&pen,tempX,tempY,tempW,tempH);//副本画布上绘制矩形
}
break;
case 2://绘制椭圆,方法与矩形类似,省略
break;
case 3://绘制曲线,略
break;
}
Graphics gp(this->GetSafeHwnd());
gp.DrawImage(tempBitmap,0,0);//将画布副本复制到屏幕
delete tempBitmap; delete pgp;
CView::OnMouseMove(nFlags, point);
}
(9)建立鼠标左键按下事件响应函数,并添加如下代码:
void CDBufferView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
::SetCursor(s_Cross);
Graphics gp(this->GetSafeHwnd());
PointF* tempPoint;
CPoint tempP;
switch(this->m_nDrawTool)
{
case 0://在虚拟画布上画直线并将虚拟画布复制到屏幕上
if(m_nButtonDown>=1)
{
tempPoint=new PointF[2];
tempP=m_PointList.GetAt(0);
tempPoint[0].X=(REAL)tempP.x;
tempPoint[0].Y=(REAL)tempP.y;
tempPoint[1].X=(REAL)point.x;
tempPoint[1].Y=(REAL)point.y;
Pen pen(Color::Black,1.0f);
m_pGP->DrawLine(&pen,tempPoint[0],tempPoint[1]);
m_nButtonDown=0;
delete[] tempPoint;
}
gp.DrawImage(m_pBitmap,0,0);//复制缓存区数据到屏幕
break;
case 1://在虚拟画布画矩形并复制到屏幕上,略
break;
case 2://在虚拟画布画椭圆并复制到屏幕上,略
break;
}
CView::OnLButtonUp(nFlags, point);
}
程序在Visual Studio2005+Windows2003环境调试通过,下面是运行效果图,如图2,图3,图4,图5所示。
图2 画直线 |
图3 画矩形 |
图4 画椭圆 |
图5 画曲线 |
六、总结 在交互式绘图系统中,使用橡皮筋技术是经常遇到的一个实际问题,而GDI+具有比GDI更方便的开发方法和更美观的图像效果,在软件开发中应用得越来越广泛。本文应用双缓存技术解决在GDI+绘图过程中的橡皮筋技术问题,使图形的绘制过程更加直观。
|