VC++图形编程,WinGdi和GdiPlus是少不了的,本文记录一下工作中用到的一些绘图知识和相关代码:
1.获取窗口DC的两种方式比较
BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和ReleaseDC()并不删除也不能使无效区域有效,因此当程序跳出 WM_PAINT 时 ,无效区域仍然存在。
系统就回不断发送WM_PAINT消息,于是程序不断处理WM_PAINT消息。
BeginPaint、EndPaint会告诉GDI内部,这个窗口需要重画的地方已经重画了,这样WM_PAINT处理完返回给系统后,系统不会再重发WM_PAINT,
而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通知你的重画命令还没有执行或者执行出错,
所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死
2.利用内存DC提高绘图效率
绘图比较耗时,优化的方式是先在内存DDC中绘图,最后把内存DC的内容复制到显示设备DC中
样例代码:
void DrawOnDc(HWND hWnd)
{
int SCREEN_WIDTH = 100;
int SCREEN_HEIGHT = 50;
PAINTSTRUCT ps;
HDC hdc;
//获取屏幕显示DC
hdc = BeginPaint(hWnd, &ps);
//创建内存DC
HDC hdcMem = CreateCompatibleDC(hdc);
//创建一个bmp内存空间
HBITMAP hBmp = CreateCompatibleBitmap(hdc, SCREEN_WIDTH, SCREEN_HEIGHT);
// HANDLE hBmp= LoadImage(g_hInst_MainWnd,MAKEINTRESOURCE(IDB_MAINWND),IMAGE_BITMAP,0,0,0);
//将bmp内存空间分配给内存DC
HGDIOBJ hOldSel = SelectObject(hdcMem, hBmp);
//这是使用者需要绘制的画面,全部往内存DC绘制
Rectangle(hdcMem, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
// 内存DC上绘制
// ...
//将内存DC的内容复制到屏幕显示DC中,完成显示
BitBlt(hdc, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, hdcMem, 0, 0, SRCCOPY);
//清除资源
SelectObject(hdcMem, hOldSel);
DeleteDC(hdcMem);
EndPaint(hWnd, &ps);
}
3. WinGdi绘制图形矩形区域:
void DrawFillRectangle(HWND hwnd)
{
WORD dotPatternBmp[8] = { 0x00aa, 0x0055, 0x00aa, 0x0055, 0x00aa, 0x0055, 0x00aa, 0x0055 };
HBITMAP bmpMovePattern = nullptr;
HBRUSH brMovePattern = nullptr;
bmpMovePattern = CreateBitmap(8, 8, 1, 1, dotPatternBmp);
brMovePattern = CreatePatternBrush(bmpMovePattern);
POINT pt = { 100, 100 };
SIZE size = { 100, 100 };
HDC hdc = GetDC(hwnd);
::SetBrushOrgEx(hdc, pt.x, pt.y, 0);
HBRUSH hbrushOld = (HBRUSH)::SelectObject(hdc, brMovePattern);
::PatBlt(hdc, pt.x, pt.y, size.cx, size.cy, PATINVERT);
::SelectObject(hdc, hbrushOld);
::ReleaseDC(hwnd, hdc);
}
4. WinGDI绘制矩形的方法
Rectangle
PatBlt
5. 图片处理:
透明:
AlphaBlend: 支持透明且等比或者不等比缩放
非透明:
BitBlt : 1:1等比,不支持缩放
StretchBlt: 按照等比例了缩放
6. GdiPlus绘制直线,矩形,椭圆,带箭头直线,颜色填充矩形
6.1 绘制直线,矩形,椭圆,带箭头的直线
void PaintGraphAnnot(E_SHAPE_TYPE graphAnnotType, HDC hdc, Gdiplus::Point startPoint, Gdiplus::Point endPoint, std::vector<Gdiplus::Point>& vecPoint) {
Gdiplus::Graphics gs(hdc);
gs.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
Gdiplus::Point ptBegin = { startPoint.X, startPoint.Y };
Gdiplus::Point ptEnd = { endPoint.X, endPoint.Y };
Gdiplus::Color magentaColor(255, 67, 67);
Gdiplus::Pen magentaPen(magentaColor, 2);
vecPoint.clear();
Gdiplus::Point ptOrg;
int iWidth, iHeight;
iWidth = abs(startPoint.X - endPoint.X);
iHeight = abs(startPoint.Y - endPoint.Y);
// 确定象限
// 1
if (startPoint.X > endPoint.X && startPoint.Y > endPoint.Y)
ptOrg = ptEnd;
// 2
if (startPoint.X < endPoint.X && startPoint.Y > endPoint.Y) {
ptOrg.X = ptBegin.X;
ptOrg.Y = ptEnd.Y;
}
// 3
if (startPoint.X > endPoint.X && startPoint.Y < endPoint.Y) {
ptOrg.X = ptEnd.X;
ptOrg.Y = ptBegin.Y;
}
// 4
if (startPoint.X < endPoint.X && startPoint.Y < endPoint.Y)
ptOrg = ptBegin;
switch (graphAnnotType) {
case LINE:
gs.DrawLine(&magentaPen, ptBegin, ptEnd);
vecPoint.push_back(Point(ptBegin.X, ptBegin.Y));
vecPoint.push_back(Point(ptEnd.X, ptEnd.Y));
break;
case SQUARE: {
Gdiplus::Rect rect(ptOrg.X, ptOrg.Y, iWidth, iHeight);
if (iHeight > 0) {
gs.DrawRectangle(&magentaPen, rect);
vecPoint.push_back(Point(ptOrg.X, ptOrg.Y));
vecPoint.push_back(Point(ptOrg.X + iWidth + 2, ptOrg.Y + iHeight + 2));
}
} break;
case ELLIPSE: {
Gdiplus::Rect ellipseRect(ptOrg.X, ptOrg.Y, iWidth, iHeight);
if (iHeight > 0) {
gs.DrawEllipse(&magentaPen, ellipseRect);
vecPoint.push_back(Point(ptOrg.X, ptOrg.Y));
vecPoint.push_back(Point(ptOrg.X + iWidth + 2, ptOrg.Y + iHeight + 2));
}
} break;
case ARROW_LINE:
{
// 1.画直线
gs.DrawLine(&magentaPen, ptBegin, ptEnd);
vecPoint.push_back(Point(ptBegin.X, ptBegin.Y));
vecPoint.push_back(Point(ptEnd.X, ptEnd.Y));
// 2.画箭头
//终点画箭头
/*
int nx1 = ptBegin.X;
int ny1 = ptBegin.Y;
int nx2 = ptEnd.X;
int ny2 = ptEnd.Y;
*/
// 起点画箭头
int nx1 = ptEnd.X;
int ny1 = ptEnd.Y;
int nx2 = ptBegin.X;
int ny2 = ptBegin.Y;
double dbLineLength = sqrt(pow((double)(nx1 - nx2), 2.0) + pow((double)(ny1 - ny2), 2.0));
double fArrowAngle = 0;
double fLineLengthNew = (float)fabs(dbLineLength + 0.5);
double fOffsetY = fabs(ny2 - ny1);
double fOffsetX = fabs(nx2 - nx1);
double fSin = 0;
double fCos = 0;
int PtArrowBeginX = 0;
int PtArrowBeginY = 0;
// 分4个象限进行显示
if ((nx2 >= nx1) && (ny2 > ny1)) {
// 270 ~ 360度
fArrowAngle = FPAI_DOT_5 + atan2(1.0, fOffsetX / fOffsetY);
}
else if ((nx2 > nx1) && (ny2 <= ny1)) {
// 0 ~ 90度
fArrowAngle = FPAI_DOT_5 - atan2(1.0, fOffsetX / fOffsetY);
}
else if ((nx2 <= nx1) && (ny2 < ny1)) {
// 90 ~ 180度
fArrowAngle = FPAI_1_DOT_5 + atan2(1.0, fOffsetX / fOffsetY);
}
else if ((nx2 < nx1) && (ny2 >= ny1)) {
// 180 ~ 270度
fArrowAngle = FPAI_1_DOT_5 - atan2(1.0, fOffsetX / fOffsetY);
}
fSin = sin(fArrowAngle);
fCos = cos(fArrowAngle);
PtArrowBeginX = nx1 + (int)(fSin * fLineLengthNew);
PtArrowBeginY = (int)fabs(fCos * fLineLengthNew - ny1);
ptBegin = { nx1 + (int)(fSin * (fLineLengthNew - 20) - fCos * 20.0),
(int)fabs(fCos * (fLineLengthNew - 20) - fSin * -20.0 - ny1) };
ptEnd = { PtArrowBeginX, PtArrowBeginY };
gs.DrawLine(&magentaPen, ptBegin, ptEnd);
/*
gs.DrawLine(&magentaPen, nx1 + (int)(fSin * (fLineLengthNew - 20) - fCos * 20.0),
(int)fabs(fCos * (fLineLengthNew - 20) - fSin * -20.0 - ny1), PtArrowBeginX, PtArrowBeginY);
*/
vecPoint.push_back(Point(ptBegin.X, ptBegin.Y));
vecPoint.push_back(Point(ptEnd.X, ptEnd.Y));
ptBegin = { nx1 + (int)(fSin * (fLineLengthNew - 20) + fCos * 20.0),
(int)fabs(fCos * (fLineLengthNew - 20) - fSin * 20.0 - ny1) };
ptEnd = { PtArrowBeginX, PtArrowBeginY };
gs.DrawLine(&magentaPen, ptBegin, ptEnd);
/*
gs.DrawLine(&magentaPen, nx1 + (int)(fSin * (fLineLengthNew - 20) + fCos * 20.0),
(int)fabs(fCos * (fLineLengthNew - 20) - fSin * 20.0 - ny1), PtArrowBeginX, PtArrowBeginY);
*/
vecPoint.push_back(Point(ptBegin.X, ptBegin.Y));
vecPoint.push_back(Point(ptEnd.X, ptEnd.Y));
}
break;
default:
break;
}
TCHAR tmpBuf[1024] = { 0 };
swprintf_s(tmpBuf, 1024, L"startPoint(%d, %d) endPoint(%d, %d) \n", ptBegin.X, ptBegin.Y, ptEnd.X, ptEnd.Y);
OutputDebugString(tmpBuf);
}
6.2 绘制颜色填充的矩形
void DrawMovePatternEx(HDC hdc, POINT pt, SIZE size) {
Gdiplus::Graphics gs(hdc);
Gdiplus::Color color(100, 179, 179, 179);
Gdiplus::SolidBrush soBrush(color);
gs.FillRectangle(&soBrush, pt.x, pt.y, size.cx, size.cy);
}