首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么绘制到隐藏的HDC与绘制到GetDC返回的HDC (HWND)时的结果不同?

为什么绘制到隐藏的HDC与绘制到GetDC返回的HDC (HWND)时的结果不同?
EN

Stack Overflow用户
提问于 2022-11-10 18:41:19
回答 1查看 70关注 0票数 3

我有两种方法,paintDoubleBuffered和paint。他们都应该在屏幕上画这个图像:

该图像由大约12个较小的图像组成,每个大小为256x256平铺在一起。

我的标准绘画方法和预期的一样。下面是:

代码语言:javascript
复制
void MainWindow::paint(HWND hwnd) {

    HDC hdc{GetDC(hwnd)};
    paint(hwnd, hdc);
    ReleaseDC(hwnd, hdc);

}

void MainWindow::paint(HWND hwnd, HDC hdc) {
    constexpr INT img_width{ MDNR_Map::pannel_width };
    constexpr INT img_height{ MDNR_Map::pannel_height };

    const INT width{ GetDeviceCaps(hdc, HORZRES) };
    const INT height{ GetDeviceCaps(hdc, VERTRES) };

    const INT num_width_pannels{ (width / img_width) + 1 };
    const INT num_height_pannels{ (height / img_height) + 1 };

    Gdiplus::Graphics g(hdc);

    g.SetCompositingMode(CompositingMode::CompositingModeSourceCopy);

    g.SetInterpolationMode(InterpolationMode::InterpolationModeNearestNeighbor);

    for (INT y = 0; y < num_height_pannels; y++) {
        for (INT x = 0; x < num_width_pannels; x++) {

            Location_t get_loaction(x + map_location.x, y + map_location.y, map_location.layer);
            const IMG_t v{ mdnr_map.get(get_loaction) };

            const Point drawPoint((INT)(img_width * x), (INT)(img_height * y));

            Status stat{ g.DrawImage(v, drawPoint) };

            if (stat != Status::Ok)
            {
                throw std::runtime_error(":(");
            }


        }
    }
}

这个油漆方法的问题是,mdnr_map.get是一个io绑定调用,可能需要几微秒。因为我需要叫它12次,它会导致闪烁。

为了解决这个问题,我尝试编写一个双缓冲的油漆方法,如下所示:

代码语言:javascript
复制
void MainWindow::paintDoubleBuffered(HWND hwnd) {

    // Get DC for window
    HDC hdc{ GetDC(hwnd) };

    const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
    const INT win_height{ GetDeviceCaps(hdc, VERTRES) };

    // Create an off-screen DC for double-buffering
    HDC hdcMem{ CreateCompatibleDC(hdc) };

    HBITMAP hbmMem{ CreateCompatibleBitmap(hdc, win_width, win_height) };

    HANDLE hOld{ SelectObject(hdcMem, hbmMem) };

    // Draw into hdcMem here
    paint(hwnd, hdcMem);

    // Transfer the off-screen DC to the screen
    BitBlt(hdc, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);

    // Free-up the off-screen DC
    SelectObject(hdcMem, hOld);

    DeleteObject(hbmMem);
    DeleteDC(hdcMem);
}

但是,这样做不起作用,反而产生了这种令人憎恶的图像:

只要稍微戳一下,我就能发现,如果我把图像大小乘以1.5来改变我的双缓冲油漆方法,图像就不再那么乱了,但现在放大了1.5倍。

代码语言:javascript
复制
void MainWindow::paintDoubleBuffered(HWND hwnd) {

    // Get DC for window
    HDC hdc{ GetDC(hwnd) };

    const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
    const INT win_height{ GetDeviceCaps(hdc, VERTRES) };

    // Create an off-screen DC for double-buffering
    HDC hdcMem{ CreateCompatibleDC(hdc) };

    HBITMAP hbmMem{ CreateCompatibleBitmap(hdc, win_width, win_height) };

    HANDLE hOld{ SelectObject(hdcMem, hbmMem) };

    // Draw into hdcMem here
    
    constexpr INT img_width{ MDNR_Map::pannel_width + 128 }; // MDNR_Map::pannel_width is 256
    constexpr INT img_height{ MDNR_Map::pannel_height + 128}; // MDNR_Map::pannel_height is 256

    const INT num_width_pannels{ (win_width / img_width) + 1 };
    const INT num_height_pannels{ (win_height / img_height) + 1 };

    Gdiplus::Graphics g(hdcMem);

    g.SetCompositingMode(CompositingMode::CompositingModeSourceCopy);

    g.SetInterpolationMode(InterpolationMode::InterpolationModeNearestNeighbor);

    for (INT y = 0; y < num_height_pannels; y++) {
        for (INT x = 0; x < num_width_pannels; x++) {

            Location_t get_loaction(x + map_location.x, y + map_location.y, map_location.layer);
            Gdiplus::Bitmap* pannel{ mdnr_map.get(get_loaction) };

            const Point drawPoint((INT)(img_width * x), (INT)(img_height * y));

            Status stat{ g.DrawImage(pannel, drawPoint) };
            if (stat != Status::Ok)
            {
                throw std::runtime_error(":(");
            }

        }
    }

    // Transfer the off-screen DC to the screen
    BitBlt(hdc, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);

    // Free-up the off-screen DC
    SelectObject(hdcMem, hOld);

    DeleteObject(hbmMem);
    DeleteDC(hdcMem);
}

我的问题是为什么CreateCompatibleBitmap返回的HDC与GetDC?返回的HDC产生不同的结果?

我试过了: BltBlt的所有光栅操作代码.我检查过临时的HDC和窗口的大小是一样的。我试过替换代码片段

代码语言:javascript
复制
const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
const INT win_height{ GetDeviceCaps(hdc, VERTRES) };

使用

代码语言:javascript
复制
RECT rect;
GetWindowRect(hwnd, &rect);

const INT win_width{ rect.right - rect.left };
const INT win_height{ rect.bottom - rect.top };

我还在绘图之前调用了SetProcessDPIAware()。

根据@Paul的反馈,我重写了我的paintDoubleBuffered方法如下,注意,我在对象构造函数中调用了BufferedPaintInit:

代码语言:javascript
复制
void MainWindow::paintDoubleBuffered(HWND hwnd) {

    PAINTSTRUCT ps;
    HDC hdc{ BeginPaint(hwnd, &ps)};

    RECT sz;
    GetWindowRect(hwnd, &sz);

    BP_PAINTPARAMS paintParams = { 0 };

    paintParams.cbSize = sizeof(paintParams);
    paintParams.dwFlags = BPPF_ERASE;
    paintParams.pBlendFunction = NULL;
    paintParams.prcExclude = NULL;

    HDC hdcBuffer;

    HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hdc, &sz, BPBF_COMPATIBLEBITMAP, &paintParams, &hdcBuffer);

    if (hBufferedPaint && this->bufferedInitResult == Ok) {
        // Application specific painting code
        paint(hwnd, hdcBuffer);
        EndBufferedPaint(hBufferedPaint, TRUE);
    }
    else{
        paint(hwnd, hdc);
    }

    ReleaseDC(hwnd, hdc);
}

不幸的是,这不起作用,由此产生的屏幕如下所示:

EN

回答 1

Stack Overflow用户

发布于 2022-11-11 22:41:27

问题最终不是在双重缓冲的方法中,而是在我的call方法中对Graphics::DrawImage(Image*, Gdiplus::Point)的调用中。更改为DrawImage(Image* image, INT x, INT y, INT width, INT height)修复了缩放问题。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74393885

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档