我有一个使用WS_EX_LAYERED
窗口样式创建的窗口。我目前正在使用GDI +绘制内存位图,并使用UpdateLayeredWindow
更新分层窗口的图形内容。
这是我的代码片段:
void Redraw(HWND hWnd, int width, int height) {
static bool floppy = true;
floppy = !floppy;
HDC hScreenDC = GetDC(HWND_DESKTOP);
HDC hMemDC = CreateCompatibleDC(hScreenDC);
HBITMAP hBmp = CreateCompatibleBitmap(hScreenDC, width, height);
HGDIOBJ hObj = SelectObject(hMemDC, hBmp);
Graphics gfx(hMemDC);
SolidBrush b(Color(254, (floppy ? 255 : 0), (floppy ? 0 : 255), 0));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
BLENDFUNCTION blend;
blend.BlendOp = AC_SRC_OVER;
blend.BlendFlags = 0;
blend.SourceConstantAlpha = 255;
blend.AlphaFormat = AC_SRC_ALPHA;
POINT src = { 0, 0 };
SIZE size;
size.cx = width;
size.cy = height;
Assert(UpdateLayeredWindow(
hWnd,
hScreenDC,
NULL,
&size,
hMemDC,
&src,
RGB(0, 0, 0),
&blend,
ULW_ALPHA
));
SelectObject(hMemDC, hObj);
DeleteObject(hBmp);
DeleteDC(hMemDC);
ReleaseDC(HWND_DESKTOP, hScreenDC);
}
创建SolidBrush
时,我为alpha组件指定了值254。这导致99.6%的不透明填充,这不是我想要的。
当我指定255作为alpha分量时,似乎没有填充;我的窗户变得完全透明。这是一个问题,因为我希望绘制100%不透明的形状,但我也想绘制一些不是。
答案 0 :(得分:3)
FillRectangle
似乎有一些qwerks。当我们观察到FillEllipse
使用其{alpha}为255的SolidBrush
时,会变得明显(不透明)。
以下是我提出的两个解决方法,每个都解决了我的问题:
致电 FillRectangle
两次
SolidBrush b(Color(254, 255, 0, 0));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
gfx.FillRectangle(&b, Rect(0, 0, width, height));
由于相同的区域被填充两次,它们将混合并创建RGB(255,0,0),而不管窗口后面的内容(它现在是100%不透明)。我不喜欢这种方法,因为它需要绘制两个矩形。
使用 FillPolygon
代替
与FillEllipse
一样,FillPolygon
似乎没有颜色问题,除非您这样称呼:
SolidBrush b(Color(255, 255, 0, 0));
Point points[4];
points[0] = Point(0, 0);
points[1] = Point(width, 0);
points[2] = Point(width, height);
points[4] = Point(0, height);
gfx.FillPolygon(&b, points, 4); //don't copy and paste - this won't work
以上代码将生成100%透明窗口。我猜这是由于某种形式的优化将调用传递给FillRectangle
。或者 - 很可能 - FillPolygon
存在一些问题,由FillRectangle
调用。但是,如果您向数组添加额外的Point
,则可以绕过它:
SolidBrush b(Color(255, 255, 0, 0));
Point points[5];
points[0] = Point(0, 0);
points[1] = Point(0, 0); //<-
points[2] = Point(width, 0);
points[3] = Point(width, height);
points[4] = Point(0, height);
gfx.FillPolygon(&b, points, 5);
上面的代码确实会绘制出100%不透明的形状,这可以解决我的问题。
答案 1 :(得分:1)
UpdateLayeredWindow()
需要预先乘以alpha的位图:
请注意,API使用预乘alpha,这意味着红色, 位图中的绿色和蓝色通道值必须预乘 alpha通道值。例如,如果alpha通道值为x, 红色,绿色和蓝色通道必须乘以x并分开 在通话之前通过0xff。
您可以使用Bitmap::ConvertFormat()
将位图转换为预乘(格式为PixelFormat32bppPARGB
)。