CCreateArc类描述如何交互绘制圆弧。本程序采用圆心、起点和终点三点绘制圆弧,所以用鼠标交互绘图时需要确定这3个点的位置。其大体思路是:前两次单击鼠标左键分别定义圆心和起点,这两点定义以后是不会变的;然后定义圆弧的终点。终点不能直接定义,因为在绘图区我们基本上不能直接获得终点的准确位置,但可以间接得到终点坐标。具体方法是根据第3点的方位角和由前两点得到的半径,计算出终点的准确位置。所以我们说的用圆心、起点和终点绘制圆弧从本质上讲应该是用圆心、起点和第3点绘制圆弧。
与前面的CCreateLine类和CCreateCircle类一样,CCreateArc类也实现了ICommand 接口。类中用到4个局部变量,m_Step定义鼠标左键的单击次数,m_Center、m_Begin和m_End分别记录圆弧的圆心、起点和终点的坐标。
LButonDown方法实现了 Command接口的LButondown方法。第一次单击鼠标左键时,定义圆心的位置,将当前点的坐标赋给m_Center。第2次单击鼠标左键时,确定圆弧起点的位置,并将该位置也赋给m_End对象,作为终点。所以,在初始情况下,圆弧的起点和终点是重合的。然后代码中用前面定义的3个点构造了一个暂时的CArc对象,并用拖曳模式绘制了该对象,然后注销。为什么要这样做,将在介绍MouseMove方法时介绍。第3次单击鼠标左键时,清除圆心到起点的橡皮线、圆心到终点的橡皮线和橡皮弧,以正常模式绘制最后生成的圆弧。将m_Step归0。
public class CCreateArc:ICommand
{
private int m_Step;
private PointF m_Center;
private PointF m_Begin;
private PointF m_End;
public CCreateArc()
{
//
// TODO: 在此处添加构造函数逻辑
//
}
public void LButtonDown(Graphics g,PointF aPos,ArrayList ges,ArrayList geSels)
{
//记录鼠标左键的单击次数
m_Step+=1;
switch(m_Step)
{
case 1: //第1次单击鼠标左键
m_Center=aPos;
break;
case 2:
m_Begin=aPos;
m_End=aPos;
CArc tempArc1=new CArc(m_Center, aPos, aPos);
tempArc1.Draw(g, DrawMode.Drag);
tempArc1 =null;
break;
case 3:
//清除最后一次拖动时圆心到起点的橡皮线
CLine tempLine1=new CLine(m_Center,m_Begin);
tempLine1.Draw(g,DrawMode.Drag);
tempLine1=null;
//清除最后一次拖动时圆心到终点的橡皮线
CLine tempLine2=new CLine(m_Center,m_End);
tempLine2.Draw(g,DrawMode.Drag);
tempLine2=null;
//清除最后一次拖动时显示的橡皮弧
CArc tempArc=new CArc(m_Center,m_Begin,m_End);
tempArc.Draw(g,DrawMode.Drag );
tempArc=null;
//绘当前位置的圆弧
CArc newArc=new CArc(m_Center,m_Begin,aPos);
newArc.Draw(g,DrawMode.Normal);
ges.Add(newArc);
m_Step=0;
break;
}
}
}
MouseMove 方法实现了ICommand接口的MouseMove方法,用于描述鼠标在绘图区移动时的绘图行为。鼠标移动时,需要不断地清除上一条圆心到终点的橡皮线、上一条橡皮弧,并绘制当前的圆心到终点的橡皮线和橡皮弧。需要注意的是,在介绍LButtonDown 方法时说过,在初始状态下,圆弧的起点和终点是重合的。既然是重合的,那么,绘出的是一个点还是一个圆呢?读者朋友不妨测试一下,结果是一个圆。但绘制橡皮弧时,首先要清除上一个橡皮弧,由于在鼠标第1次移动以前并没有绘圆弧,所以没有上一个橡皮弧可供清除。结果如何呢?由于采用拖曳模式绘制,它不但没有清除,实际上还绘了一个圆。这样,后面的橡皮弧绘制将全部反向,实际上是逆时针方向绘制的,显示在屏幕上却是顺时针方向绘制。所以,在前面的LButtonDown方法中,在第2次单击以后就根据给定的3个点以拖曳模式绘了一个圆,等着MouseMove方法来清除。当前橡皮线和橡皮弧绘制完毕以后,不要忘了将当前点设置为m_End。
public void MouseMove(Graphics g,PointF aPos)
{
switch(m_Step)
{
case 2:
PointF prePos=new PointF();
PointF curPos=new PointF();
prePos=m_End;
curPos=aPos;
//清除上一条圆心到终点的橡皮线
CLine tempLine1=new CLine(m_Center,prePos);
tempLine1.Draw(g,DrawMode.Drag);
tempLine1=null;
//清除上一条橡皮弧
CArc tempArc1=new CArc(m_Center,m_Begin,prePos);
tempArc1.Draw(g,DrawMode.Drag);
tempArc1=null;
//绘当前圆心到终点的橡皮线
CLine tempLine2=new CLine(m_Center,curPos);
tempLine2.Draw(g,DrawMode.Drag);
tempLine2=null;
//绘当前位置的橡皮弧
CArc tempArc2=new CArc(m_Center, m_Begin, curPos);
tempArc2.Draw(g, DrawMode.Drag);
tempArc2 = null;
m_End=curPos;
break;
}
}
RButtonDown方法实现了ICommand接口的RButtonDown方法,它实现对当前未完成工作的取消。取消操作需要从屏幕上清除圆心到起点的橡皮线、圆心到终点的橡皮线和橡皮弧,并将m_Step的值设为0。
//单击鼠标右键时的绘图行为
public void RButtonDown(Graphics g,PointF aPos)
{
if(m_Step==2)
{
//清除圆心到起点的橡皮线
CLine tempLine1=new CLine(m_Center,m_Begin);
tempLine1.Draw(g,DrawMode.Drag);
tempLine1=null;
//清除圆心到终点的橡皮线
CLine tempLine2=new CLine(m_Center,m_End);
tempLine2.Draw(g,DrawMode.Drag);
tempLine2=null;
//清除橡皮弧
CArc tempArc=new CArc(m_Center,m_Center,m_End);
tempArc.Draw(g,DrawMode.Drag);
tempArc=null;
}
m_Step=0;
}