MFC中实现的画箭头算法 (Arrow in MFC)
在以前做的程序中,曾经需要使用程序来画出一个箭头
但是自己想出的算法又不是太通用
所以在codeproject中寻找到一个这样的算法,在这里介绍一下
可以改变三角形大小,顶点角度,是否填充和填充颜色等
但是画出的箭头还是不够美观….呵呵,还好吧
其中填充是代表箭头内是否填充颜色
先来看声明和实现
/////////////////////// //使用一个结构体来存储相关的信息 //Defines the attributes of an arrow. typedef struct tARROWSTRUCT { int nWidth; // width (in pixels) of the full base of the arrowhead float fTheta; // angle (in radians) at the arrow tip between the two // sides of the arrowhead bool bFill; // flag indicating whether or not the arrowhead should be // filled } ARROWSTRUCT; /////////////////////// //函数声明 // Draws an arrow, using the current pen and brush, from the current position // to the passed point using the attributes defined in the ARROWSTRUCT. void ArrowTo(HDC hDC, int x, int y, ARROWSTRUCT *pArrow); void ArrowTo(HDC hDC, const POINT *lpTo, ARROWSTRUCT *pArrow); /////////////////////// //画箭头函数实现 void CMyDialog::ArrowTo(HDC hDC, int x, int y, ARROWSTRUCT *pA) { POINT ptTo = {x, y}; ArrowTo(hDC, &ptTo, pA); } void CMyDialog::ArrowTo(HDC hDC, const POINT *lpTo, ARROWSTRUCT *pA) { POINT pFrom; POINT pBase; POINT aptPoly[3]; float vecLine[2]; float vecLeft[2]; float fLength; float th; float ta; // get from point MoveToEx(hDC, 0, 0, &pFrom); // set to point aptPoly[0].x = lpTo->x; aptPoly[0].y = lpTo->y; // build the line vector vecLine[0] = (float) aptPoly[0].x - pFrom.x; vecLine[1] = (float) aptPoly[0].y - pFrom.y; // build the arrow base vector - normal to the line vecLeft[0] = -vecLine[1]; vecLeft[1] = vecLine[0]; // setup length parameters fLength = (float) sqrt(vecLine[0] * vecLine[0] + vecLine[1] * vecLine[1]); th = pA->nWidth / (2.0f * fLength); ta = pA->nWidth / (2.0f * (tanf(pA->fTheta) / 2.0f) * fLength); // find the base of the arrow pBase.x = (int) (aptPoly[0].x + -ta * vecLine[0]); pBase.y = (int) (aptPoly[0].y + -ta * vecLine[1]); // build the points on the sides of the arrow aptPoly[1].x = (int) (pBase.x + th * vecLeft[0]); aptPoly[1].y = (int) (pBase.y + th * vecLeft[1]); aptPoly[2].x = (int) (pBase.x + -th * vecLeft[0]); aptPoly[2].y = (int) (pBase.y + -th * vecLeft[1]); MoveToEx(hDC, pFrom.x, pFrom.y, NULL); // draw we're fillin'... if(pA->bFill) { LineTo(hDC, aptPoly[0].x, aptPoly[0].y); Polygon(hDC, aptPoly, 3); } // ... or even jes chillin'... else { LineTo(hDC, pBase.x, pBase.y); LineTo(hDC, aptPoly[1].x, aptPoly[1].y); LineTo(hDC, aptPoly[0].x, aptPoly[0].y); LineTo(hDC, aptPoly[2].x, aptPoly[2].y); LineTo(hDC, pBase.x, pBase.y); MoveToEx(hDC, aptPoly[0].x, aptPoly[0].y, NULL); } }
再来看调用实现(加一层封装更加适用)
///////////////////// //封装调用函数实现(其实还是有很大的扩展空间的) void CMyDialog::ArrowTo( CDC *pDC, //画刷 CPoint point, //终点坐标 int nPenStyle, //线样式 int nPenWidth, //线宽度 COLORREF color, //颜色 int nWidth, //三角形底边宽度 float fTheta, //三角形顶角角度 bool bFill //是否填充颜色 ) { ARROWSTRUCT a; a.nWidth = nWidth; //三角形底边宽度 a.fTheta = fTheta; //三角形顶角角度 a.bFill = bFill; //是否填充颜色 CPen* pOldPen; CPen pen(nPenStyle,nPenWidth,color); pOldPen = pDC->SelectObject(&pen); CBrush br,*pbrOld; br.CreateSolidBrush(color); pbrOld = pDC->SelectObject(&br); ArrowTo(*pDC,point.x,point.y,&a); //调用画箭头函数 pDC->SelectObject(pOldPen); pDC->SelectObject(pbrOld); }
OK,完成
源程序地址: 以前找的…现在去找居然找不到了….
Trackback from your site.
(2)条评论
wupei
| #
本来的功能函数是有两个函数的,我又添加了一层封装,这样就是三个函数,根据参数可以看出调用方式
调用关系,为一层一层往里进的..
下面我列一下:
1. 调用:
void CMyDialog::ArrowTo(
CDC *pDC, //画刷
CPoint point, //终点坐标
int nPenStyle, //线样式
int nPenWidth, //线宽度
COLORREF color, //颜色
int nWidth, //三角形底边宽度
float fTheta, //三角形顶角角度
bool bFill //是否填充颜色
)
2. 调用 void ArrowTo(HDC hDC, int x, int y, ARROWSTRUCT *pArrow);
3. 调用 void ArrowTo(HDC hDC, const POINT *lpTo, ARROWSTRUCT *pArrow);
关于你说的起始点问题,如下:
CDC 本身就保留着当前所指示的点的,调用 dc.MoveTo(yourPoint);
原型: CDC::MoveTo
CPoint MoveTo(
int x,
int y
);
CPoint MoveTo(
POINT point
);
Parameters
x
Specifies the logical x-coordinate of the new position.
y
Specifies the logical y-coordinate of the new position.
point
Specifies the new position. You can pass either a POINT structure or a CPoint object for this parameter.
回复
东方红
| #
程序中的起点在哪设置,我琢磨了一天,还没测出来。是pFrom吗?如果是为什么我把它的值改变后还是一样从(0,0)点出发呢?怎样才能改变起点,使它不从(0,0)出发?拜求!!!!!
回复