【问题标题】:Drawing to and creation of memory buffer (Windows GDI)绘制和创建内存缓冲区 (Windows GDI)
【发布时间】:2015-01-25 11:25:41
【问题描述】:

我正在尝试在一个窗口内显示用户监视器,该窗口全部缩小到可能的最大尺寸。目前它不使用缓冲区,我不确定如何根据需要创建缓冲区。

当它动态绘制监视器时,不必再用 WM_ERASEBKGND 重新绘制整个窗口白色,当它被调整大小时,我认为,经过大量阅读后,将整个“虚拟桌面”的比例表示为内存 DIB 将是最好的方法:因此我可以填充监视器之间的空白区域,从而不必重新绘制它们。

一个多部分的问题。是否按照建议创建一个内存规模的虚拟桌面,可以将 BitBlt 用于显示器?为此,我会使用 CreateDIBSection 吗?

目前我的 WM_PAINT 如下所示:

    hdc = BeginPaint(hwnd, &ps);

    innerBorder = 2;
    additional = 350;
    ratio = (static_cast<double>(sA.getDesktop()->right - sA.getDesktop()->left) / (sA.getDesktop()->bottom - sA.getDesktop()->top));

    cxMax = max((innerBorder * 2), min((cA.right - border), (((cA.bottom - border - additional) * ratio))));
    cyMax = max((innerBorder * 2) , min((cA.bottom - border - additional), (((cA.right - border) / ratio))));

    cxBorder = (cA.right - cxMax) / 2;

    SelectObject(hdc, GetStockObject(DC_PEN));
    SelectObject(hdc, GetStockObject(DC_BRUSH));

    SetDCPenColor(hdc, RGB(255, 255, 255));

    //Draw Borders around virtual desktop
    Rectangle(hdc, cA.left, cA.top, cxBorder, cA.bottom);
    Rectangle(hdc, cA.right - cxBorder, cA.top, cA.right, cA.bottom);

    //Draw Borders around virtual desktop
    Rectangle(hdc, cxBorder, cA.top, cA.right - cxBorder, (border / 2));
    Rectangle(hdc, cxBorder, cyMax + (border / 2), cA.right - cxBorder, cA.bottom);

    for (i = 0; i < sA.getNumberOfMonitors(); i++)
    {
        rT = {
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.left - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.top - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.right - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder - innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.bottom - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) - innerBorder,
        };

        SetDCPenColor(hdc, RGB(255, 255, 255));

        //Draw Borders around Monitor RECT
        Rectangle(hdc, rT.left - innerBorder, rT.top, rT.left, rT.bottom);
        Rectangle(hdc, rT.right, rT.top, rT.right + innerBorder, rT.bottom);
        Rectangle(hdc, rT.left - innerBorder, rT.bottom, rT.right + innerBorder, rT.bottom + innerBorder);
        Rectangle(hdc, rT.left - innerBorder, rT.top - innerBorder, rT.right + innerBorder, rT.top);


        //Draw Monitor RECT
        SetDCPenColor(hdc, RGB(0, 0, 0));

        Rectangle(hdc, rT.left, rT.top, rT.right, rT.bottom);

        DrawText(hdc, sA.getMonitor(i)->szDevice, strlen(sA.getMonitor(i)->szDevice), &rT, DT_CENTER | DT_BOTTOM | DT_NOPREFIX | DT_SINGLELINE);
    }

    EndPaint(hwnd, &ps);

其中大部分只是计算显示器与窗口的相对大小,还很少绘制。我确实希望它从图像中加载填充和边框。我想我几乎撞到了一堵砖墙。我不确定如何继续创建内存缓冲区。

编辑:我创建内存缓冲区的众多尝试之一,这会产生单色位图。

    hdcDisplay = BeginPaint(hwnd, &ps);
    hdcBuffer = CreateCompatibleDC(hdcDisplay);

    innerBorder = 2;
    additional = 350;
    ratio = (static_cast<double>(sA.getDesktop()->right - sA.getDesktop()->left) / (sA.getDesktop()->bottom - sA.getDesktop()->top));

    cxMax = max((innerBorder * 2), min((cA.right - border), (((cA.bottom - border - additional) * ratio))));
    cyMax = max((innerBorder * 2) , min((cA.bottom - border - additional), (((cA.right - border) / ratio))));

    cxBorder = (cA.right - cxMax) / 2;

    hBitmapDraw = CreateCompatibleBitmap(hdcDisplay, cxMax, cyMax);
    hBitmapPrevious = static_cast<HBITMAP>(SelectObject(hdcBuffer, hBitmapDraw));
    GetObject(hBitmapDraw, sizeof(BITMAP), &bmpDraw);

    BITMAPINFOHEADER bmpInfo;

    bmpInfo.biSize = sizeof(BITMAPINFOHEADER);
    bmpInfo.biWidth = cxMax;
    bmpInfo.biHeight = cyMax;
    bmpInfo.biPlanes = 1;
    bmpInfo.biBitCount = 32;
    bmpInfo.biCompression = BI_RGB;
    bmpInfo.biSizeImage = 0;
    bmpInfo.biXPelsPerMeter = 0;
    bmpInfo.biYPelsPerMeter = 0;
    bmpInfo.biClrUsed = 0;
    bmpInfo.biClrImportant = 0;

    //pBitmapBits = (BYTE*)malloc(sizeof(BYTE)* cxMax * 3 * cyMax);
    //hBitmapDraw = CreateDIBSection(hdcDisplay, (BITMAPINFO *)&bmpInfo, DIB_RGB_COLORS, NULL, NULL, 0);
    SelectObject(hdcBuffer, hBitmapDraw);

    SelectObject(hdcBuffer, GetStockObject(DC_PEN));
    SelectObject(hdcBuffer, GetStockObject(DC_BRUSH));

    SetDCPenColor(hdcBuffer, RGB(255, 255, 255));

    for (i = 0; i < sA.getNumberOfMonitors(); i++)
    {
        rT = {
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.left - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.top - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) + innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.right - sA.getDesktop()->left) / (sA.getDesktop()->right - sA.getDesktop()->left)) * cxMax) + cxBorder - innerBorder,
            ((static_cast<float>(sA.getMonitor(i)->rcMonitor.bottom - sA.getDesktop()->top) / (sA.getDesktop()->bottom - sA.getDesktop()->top)) * cyMax) + (border / 2) - innerBorder,
        };

        SetDCPenColor(hdcBuffer, RGB(255, 255, 255));

        //Draw Borders
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.top, rT.left, rT.bottom);
        Rectangle(hdcBuffer, rT.right, rT.top, rT.right + innerBorder, rT.bottom);
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.bottom, rT.right + innerBorder, rT.bottom + innerBorder);
        Rectangle(hdcBuffer, rT.left - innerBorder, rT.top - innerBorder, rT.right + innerBorder, rT.top);


        SetDCPenColor(hdcBuffer, RGB(0, 0, 0));

        Rectangle(hdcBuffer, rT.left, rT.top, rT.right, rT.bottom);

        DrawText(hdcBuffer, sA.getMonitor(i)->szDevice, strlen(sA.getMonitor(i)->szDevice), &rT, DT_CENTER | DT_BOTTOM | DT_NOPREFIX | DT_SINGLELINE);
    }

    BitBlt(hdcDisplay, cxBorder, (border / 2), cxMax - cxBorder, cyMax, hdcBuffer, cxBorder, border/2, SRCCOPY);
    SelectObject(hdcBuffer, hBitmapPrevious);
    DeleteDC(hdcBuffer);
    EndPaint(hwnd, &ps);

【问题讨论】:

    标签: c++ windows graphics gdi


    【解决方案1】:

    您可以通过以下方式绘制位图:

    HDC memDC = CreateCompatibleDC(hdc);
    HBITMAP memBM = CreateCompatibleBitmap(hdc, nWidth, nHeight);
    SelectObject(memDC, memBM);
    

    只需将代码中的hdc 调用替换为memDC。然后,您可以调用 StretchBlt,并将 memDC 作为源 DC。

    用完内存 DC 后,使用DeleteDC 清理它。

    MSDN 有一个使用这种技术的Scaling an image 示例。您可以将DrawBitmap 代码替换为您的绘图逻辑。

    【讨论】:

    • CreateCompatibleBitmap 默认创建单色位图,我相信要改变这一点我需要使用带有 BITMAPINFO 结构的 CreateDIBSection,这就是我感到困惑的原因。
    • @JackHammered 来自 CreateCompatibleBitmap 文档:“由 CreateCompatibleBitmap 函数创建的位图的颜色格式与 hdc 参数标识的设备的颜色格式相匹配。”如果nWidth == 0nHeight == 0,它将创建一个1x1 单色位图。如果直接操作位图的内容(例如加载/保存位图文件),则只需要 CreateDIBSection。
    • 抱歉,好像和我刚才画的黑白画一样,弄糊涂了。
    猜你喜欢
    • 2011-06-03
    • 2017-07-21
    • 2012-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    相关资源
    最近更新 更多