使用AlphaBlend绘制略透明的矩形失败了

4
我正在尝试在Native Win32 C++中绘制一个略带透明的蓝色矩形。我正在使用AlphaBlend()函数,但它没有将任何东西绘制到窗口上,什么也没有发生。
我的问题是:当我运行绘制略带透明矩形的函数时,它不会显示在我的窗口上。我感觉我做错了,也许我应该使用HBITMAP?
请告诉我需要做什么才能使我的函数在窗口上绘制一个略带透明的矩形。
另外,我知道有GDI+,但是我想暂时避免使用它,因为当我使用那个库时,我经常会遇到很多编译/包含错误,而且我想尽可能地降低依赖性,不使用那些可以为我完成所有工作的库。
bool paintRect(HDC hdc, RECT dim, COLORREF penCol, COLORREF brushCol, unsigned int opacity)
{
    HDC tempHdc         = CreateCompatibleDC(hdc);
    BLENDFUNCTION blend = {AC_SRC_OVER, 0, 127, AC_SRC_ALPHA};

    SetDCPenColor(tempHdc, RGB(255,255,0));
    SetDCBrushColor(tempHdc, RGB(255,255,0));
    Rectangle(tempHdc, dim.left, dim.top, dim.right, dim.bottom);

    return bool(AlphaBlend(hdc, dim.left, dim.top, dim.right, dim.bottom, tempHdc, dim.left, dim.top, dim.right, dim.bottom, blend)); 
}
// Usage
case WM_PAINT:
{
   HDC hdc;
   PAINTSTRUCT ps;
   hdc = BeginPaint(hwnd, &ps);

   RECT a = {0,0,100,100};
   paintRect(hdc, a, RGB(255,255,0), RGB(255,255,0), 127); // 127 is 50% transparency right?

   EndPaint(hwnd, &ps);
}
break;
2个回答

6
这将起作用:
bool paintRect(HDC hdc, RECT dim, COLORREF penCol, COLORREF brushCol, unsigned int opacity)
{
        HDC tempHdc         = CreateCompatibleDC(hdc);
        BLENDFUNCTION blend = {AC_SRC_OVER, 0, 127, 0};

        HBITMAP hbitmap;       // bitmap handle 
        BITMAPINFO bmi;        // bitmap header 
        // zero the memory for the bitmap info 
        ZeroMemory(&bmi, sizeof(BITMAPINFO));

        // setup bitmap info  
        // set the bitmap width and height to 60% of the width and height of each of the three horizontal areas. Later on, the blending will occur in the center of each of the three areas. 
        bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmi.bmiHeader.biWidth = dim.right-dim.left;
        bmi.bmiHeader.biHeight = dim.bottom-dim.top;
        bmi.bmiHeader.biPlanes = 1;
        bmi.bmiHeader.biBitCount = 32;         // four 8-bit components 
        bmi.bmiHeader.biCompression = BI_RGB;
        bmi.bmiHeader.biSizeImage = (dim.right-dim.left) * (dim.bottom-dim.top) * 4;

        // create our DIB section and select the bitmap into the dc 
        hbitmap = CreateDIBSection(tempHdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0x0);
        SelectObject(tempHdc, hbitmap);

        SetDCPenColor(tempHdc, RGB(0,0,255));
        SetDCBrushColor(tempHdc, RGB(0,0,255));
        FillRect(tempHdc, &dim, CreateSolidBrush(RGB(0,0,255)));

        return bool(AlphaBlend(hdc, dim.left, dim.top, dim.right, dim.bottom, tempHdc, dim.left, dim.top, dim.right, dim.bottom, blend)); 
}

1
请注意,我忽略了保存和重新选择旧位图(并非不重要,但与问题无关),我使用了0而不是AC_SRC_ALPHA,强制创建32位位图以满足AlphaBlend的期望,使用蓝色代替黄色,并填充矩形。 - Tony
你能更详细地解释一下 AC_SRC_ALPHA 以及将其设置为0的含义吗? - Sahil Singh
1
我认为 // 将位图的宽度和高度设置为每个水平区域宽度和高度的60%。稍后,混合将在三个区域的中心发生。 是一个复制粘贴错误。 - sergiol
这将起作用:好吧,在这里它只能通过最后一个失败的AlphaBlend产生错误87“无效参数”(而在paintRect内部没有其他调用失败)。 Win7 / 64在这里,FWIW。顺便说一句,opacity参数从未被使用。 - Sz.

3
CreateCompatibleDC函数返回一个兼容的DC,其默认位图大小为1x1。为了绘制有用的内容,首先应选择适当大小的位图。您可以使用CreateCompatibleBitmap函数。
基本上,你应该像这样做:
HDC tempHdc         = CreateCompatibleDC(hdc);
// create a bitmap of a size you need, let's say it 100x100
int width = 100;
int height = 100;
HBITMAP canvas = CreateCompatibleBitmap(hdc, width, height);
// select new bitmap into context, don't forget to save old bitmap handle
HBITMAP oldBmp = SelectObject(tepmHdc, canvas);

BLENDFUNCTION blend = {AC_SRC_OVER, 0, 127, AC_SRC_ALPHA};

SetDCPenColor(tempHdc, RGB(255,255,0));
SetDCBrushColor(tempHdc, RGB(255,255,0));
Rectangle(tempHdc, dim.left, dim.top, dim.right, dim.bottom);

bool res = AlphaBlend(hdc, dim.left, dim.top, dim.right, dim.bottom, tempHdc, dim.left, dim.top, dim.right, dim.bottom, blend);
// reset the old bitmap
SelectObect(tempHdc, oldBmp);
// canvas is no longer needed and should be deleted to avoid GDI leaks
DeleteObject(canvas);

return res;

但是,你应该认真考虑使用GDI+,尝试找出为什么会出现所有这些编译器错误并修复它们。GDI非常古老且不太友好,需要手动管理资源,使用起来相当痛苦。

祝你好运。


抢我要说的话了。确实,GDI+更像是GDI v2,加入了不错的C++特性以更好地组织它。它为您所做的事情与GDI差不多。 - chris
我已经修复了你创建位图时的HDC参数。使用“tempHdc”会导致在其上绘制时出现各种疯狂的问题,这是由于你在第一次解释为什么需要位图时所说的原因。当我不断地在我的绘画中遇到奇怪的十字线条时,这真的让我头痛不已。你还需要从“SelectObject”进行转换。 - chris

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接