【问题标题】:Create a GDI Rectangle image创建 GDI 矩形图像
【发布时间】:2014-05-13 22:01:41
【问题描述】:

我一定是做错了什么或者错过了什么,因为我真正想要的只是将一个矩形渲染成一个位图,这样我就可以在它上面进行 CreateWindowEx() 了。有谁知道我错过了什么?

HDC hdc = GetDC(hWnd);

// Create Pen and brush for the rectangle
HPEN pn = CreatePen(style, stroke, pen);
HBRUSH br = CreateSolidBrush(brush);

// Create a compatible bitmap and DC from the window DC with the correct dimensions
HDC bm_hdc = CreateCompatibleDC(hdc);
HBITMAP hImage = CreateCompatibleBitmap(bm_hdc, sz.x, sz.y);

// Select the bitmap, pen, brush into the DC
HGDIOBJ bm_obj = SelectObject(bm_hdc, hImage);
HGDIOBJ pn_obj = SelectObject(bm_hdc, pn);
HGDIOBJ br_obj = SelectObject(bm_hdc, br);

// Draw the rectangle into the compatible DC with the bitmap selected
::Rectangle(bm_hdc, xPos, yPos, xPos + xSize, yPos + ySize);

// Restore the old selections
SelectObject(bm_hdc, br_obj);
SelectObject(bm_hdc, pn_obj);
SelectObject(bm_hdc, bm_obj);

// Delete the not needed DC, pen and brush
DeleteDC(bm_hdc);
DeleteObject(br);
DeleteObject(pn);
ReleaseDC(hWnd, hdc);

// Create the window and send a message to set the static image
HWND win = CreateWindow(TEXT("STATIC"), NULL, WS_CHILD | SS_BITMAP | WS_VISIBLE, pos.x, pos.y, sz.x, sz.y, hWnd, NULL, hInst, NULL)));
HGDIOBJ obj = (HGDIOBJ)SendMessage(win, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)hImage);

// Delete the old image
if (obj)
    DeleteObject(hImage);

嗯...但这不起作用...我得到的只是一个完全黑色的区域,而不是我绘制的矩形。任何想法为什么?我是否需要在设备上下文之间创建另一个 DC 和 BitBlt()?

【问题讨论】:

  • 嗯,您的“删除旧图像”删除了新图像。旧图像是 SendMessage 的返回值
  • 谢谢...我刚刚注意到,但这似乎不是导致问题的原因。
  • 你为什么不认为@RaymondChen 是正确的?在图像有机会显示之前将其删除肯定符合给定的症状。
  • 我已经对其进行了修改,以表明 ObjHandle 实际上是 CreateWindow 返回的 HWND。在我的实际代码中,而不是这里的小附件,我实际上并没有删除对象,我仍然得到没有矩形的黑色窗口。
  • 如果你的图片有alpha像素,那么返回的位图就是控件创建的副本,否则就是你传递的原图。检查您的图像以查看是否需要删除它。如果没有 alpha 像素,则您的图像需要具有与控件相同的生命周期才能使用,相反的情况下,您需要在控件销毁后将两者都删除,否则会导致资源泄漏。

标签: c++ winapi gdi


【解决方案1】:

尝试将此行 HBITMAP hImage = CreateCompatibleBitmap(bm_hdc, sz.x, sz.y); 更改为:

HBITMAP hImage = CreateCompatibleBitmap(hdc, sz.x, sz.y);

Paul Watt为GDI写了优秀的文章,与MsImage32.dll进行图像合成。

我将您推荐给this article,因为它解决了您的问题,这里是相关的引号和代码sn-ps:

内存DC默认初始化为单色1x1像素位图。

避免常见错误

在我们远离我向您展示开始运行所需的代码之前,我想确保您安全地握住这把新剪刀。 请勿在调用 CreateCompatibleBitmap 时使用内存 DC。

...
// You may be tempted to do this; DON'T:
HDC     hMemDC = ::CreateCompatibleDC(hDC);
                                     // DON'T DO THIS
                                     //       |
                                     //       V
HBITMAP hBmp   = ::CreateCompatibleBitmap(hMemDC, width, height);
...
// TIP: Try to use the same DC to create
//      the Bitmap which you used to create the memory DC.

还记得内存DC是如何默认使用单色1x1像素位图初始化的部分吗?!

至于成员Raymond Chen的评论我相信他也是对的,但是既然你说你的实际代码不同,这是我唯一能看到的错误。

希望这会有所帮助。

最好的问候。

【讨论】:

    【解决方案2】:

    感谢大家的帮助,但实际上我自己解决了它,这也是一个愚蠢的错误......考虑这一行......:-

    ::Rectangle(bm_hdc, xPos, yPos, xPos + xSize, yPos + ySize);
    

    乍一看没有错,对吧?错误的!如果您查看我的代码,我会创建一个所需大小的兼容位图来包含我的矩形,并尝试将矩形渲染到这个位图中(在 DC 中被选中)。

    但是...我在位图中的哪个位置进行渲染? xPos 和 yPos 是矩形的窗口位置,但我没有渲染到 Window DC 是吗?!?哦!没错,xPos 和 yPos 都应该为 0,因为我正在渲染成正确大小的位图,并且在显示 Window 时,xPos 和 yPos 应该包含屏幕坐标!

    哇...真是个愚蠢的错误,感谢来自 Window 而不是兼容 DC 的 HDC 上的好位置。我确实知道内存 DC 有 1 位深度,但仍然犯了那个经典的错误。谢谢大家。

    【讨论】:

      猜你喜欢
      • 2020-01-09
      • 2019-04-07
      • 1970-01-01
      • 2010-12-07
      • 1970-01-01
      • 1970-01-01
      • 2020-04-07
      • 2013-04-27
      • 2021-12-10
      相关资源
      最近更新 更多