MFC中实现的画箭头算法 (Arrow in MFC)

作者:Wupei  |  发表时间:  |  所属分类:VC

箭头算法演示

在以前做的程序中,曾经需要使用程序来画出一个箭头

但是自己想出的算法又不是太通用

所以在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)出发?拜求!!!!!

    回复

请在这里留言: