路径可能大家在实际工作中接触的不多,它与系统默认的图形对象(pen, brush, font)不同, 它被创建后会直接选入到DC中,选入之后我们可以其描边,填充以及同时描边和填充还支持将捕捉图形的路径,并可以将路径直接转换成区域等; 我们在实现镂空字时会用到,带有背景字体的地方也会用到, 就以上所有的相对常用的方法进行展开学习.
一、API 学习
1. 创建路径
BOOL BeginPath(HDC hDC)
BOOL EndPath(HDC hDC)
这两个函数成对使用,用于获取GDI函数绘制的图形路径(轨迹)并在此区间的绘图函数不会显示到DC中
2. 路径描边和填充
BOOL StrokePath(HDC hDC)
功能: 使用当前DC中画笔对路径进行描边
BOOL FillPath(HDC hDC)
功能: 使用当前DC中画刷对路径填充
BOOL StrokeAndFillPath(HDC hDC)
功能: 使用当前DC中画笔和画刷对路径进行描边并填充
BOOL WidenPath(HDC hDC)
功能: 将当前路径加宽
3. 路径轨迹捕捉
BOOL FlattenPath(HDC hDC)
功能: 将所有的曲线转成短段
int GetPath(HDC hDC, LPPOINT lpPoints, LPBYTE lpTypes, int nSize)
功能: 获取路径中短段的起点和终点,使用此函数前要点调用FlattenPath函数(将轨迹变成条线段)
4. 路径转成区域
HRGN PathToRegion(HDC hDC)
功能: 将当前DC中的路径转成区域
二、演示代码分析
将客户区划分为6个区域,每个区域演示不同的内容
a. 路径填充
b. 路径描边
c. 路径描边和填充
d. 加宽路径并描边
e. 获取路径关键点并显示
f. 将路径转成区域并用背影填充区域
void CDemoWnd::_DemoFillPath(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
FillPath(hDC);
FlattenPath(hDC);
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DemoStrokPath(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
StrokePath(hDC);
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DemoStrokAndFillPath(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
StrokeAndFillPath(hDC);
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DemoWidenPath(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
WidenPath(hDC);
StrokePath(hDC);
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DemoPathToRegion(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
HRGN hRgn = PathToRegion(hDC);
HBITMAP hBitmap = LoadBitmap(GetModuleHandle(NULL), MAKEINTRESOURCE(IDB_BACKGROUND));
HBRUSH hBrush = CreatePatternBrush(hBitmap);
FillRgn(hDC, hRgn, hBrush);
DeleteObject(hBrush);
DeleteObject(hRgn);
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DemoGetPath(HDC hDC, RECT rtArea)
{
int nSaveDC = SaveDC(hDC);
_DrawPath(hDC, rtArea);
FlattenPath(hDC);
int nPtCount = GetPath(hDC, NULL, NULL, 0);
assert(nPtCount > 0);
POINT* ptKeyPoints = new POINT[nPtCount];
BYTE* byInfo = new BYTE[nPtCount];
int nCount = GetPath(hDC, ptKeyPoints, byInfo, nPtCount);
for (int ii = 0; ii < nPtCount; ii++)
{
Rectangle(hDC, ptKeyPoints[ii].x - 1, ptKeyPoints[ii].y - 1, ptKeyPoints[ii].x + 1, ptKeyPoints[ii].y + 1);
}
FillPath(hDC);
delete[] byInfo;
delete[] ptKeyPoints;
RestoreDC(hDC, nSaveDC);
return;
}
void CDemoWnd::_DrawPath(HDC hDC, RECT rtArea)
{
const TCHAR* szText = _T("Hello, Öйú");
//--: Font Info
LOGFONT LogFont;
GetObject(GetCurrentObject(hDC, OBJ_FONT), sizeof(LOGFONT), &LogFont);
_tcscpy(LogFont.lfFaceName, _T("΢ÈíÑźÚ"));
LogFont.lfQuality = CLEARTYPE_QUALITY;
LogFont.lfHeight = 100;
LogFont.lfWidth = 50;
HFONT hFont = CreateFontIndirect(&LogFont);
SelectObject(hDC, hFont);
SetBkMode(hDC, TRANSPARENT);
//--: Brush Info
SelectObject(hDC, GetStockObject(DC_BRUSH));
SetDCBrushColor(hDC, RGB(255, 255, 128));
//--: Pen Info
SelectObject(hDC, GetStockPen(DC_PEN));
SetDCPenColor(hDC, RGB(128, 128, 255));
RECT rtTmp = rtArea;
InflateRect(&rtTmp, -10, -10);
rtTmp.right = rtTmp.left + 50 + rtTmp.bottom - rtTmp.top;
POINT ptVertex[] = { {rtTmp.left, rtTmp.bottom},
{rtTmp.left + (rtTmp.right - rtTmp.left) / 2, rtTmp.top},
{rtTmp.right, rtTmp.bottom}
};
BeginPath(hDC);
DrawText(hDC, szText, _tcslen(szText), &rtArea, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
Polygon(hDC, ptVertex, sizeof(ptVertex) / sizeof(*ptVertex));
EndPath(hDC);
SelectObject(hDC, GetStockObject(SYSTEM_FONT));
DeleteObject(hFont);
}