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); -
}