WinGdi 和 GdiPlus绘图知识积累

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

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值