我有一个窗口,有时应该在其中有一个透明的孔,有时不应该有一个窗口。理想情况下,我们将使用setWindowrgn,但是这会禁用视觉样式,不仅看起来很丑陋,而且没有使用人均dpi dpi-evarentens正确绘制,因此我试图使用带有颜色键的分层窗口。
启用颜色键时,我首先调用SetLayeredWindowAttributes(hWnd, colorkey, 0, LWA_COLORKEY)
,然后将窗口无效,使其重新绘制。此时,窗口不应包含钥匙颜色。然后,窗口在某个时候接收WM_PAINT
,然后绘制了钥匙颜色,但是此时,窗口应该具有LWA_COLORKEY
集,因此,我希望键颜色不可见。
禁用颜色键时,我首先(同步(重新粉刷窗口,以使其不包含键颜色,然后禁用WS_EX_LAYERED
,因此,我再也不会期望看到键颜色。
但是,随着鼠标移动a的绿色,透明和背景颜色,带有以下窗口过程的窗口不断闪烁。
似乎SetLayeredWindowAttributes
也许不会立即生效(甚至在下一个WM_PAINT
之前(。如何在重新粉刷之前确保此属性已生效,或者以其他方式防止可见的关键颜色?
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static auto const colorkey = RGB(0,255,0);
static auto const hbrush = CreateSolidBrush(colorkey);
static auto transparent = false;
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
if (transparent) {
RECT rect{30,30,500,500};
FillRect(hdc, &rect, hbrush);
}
EndPaint(hWnd, &ps);
}
break;
case WM_MOUSEMOVE:
if (transparent) {
transparent = false;
RedrawWindow(hWnd, nullptr /* lprcUpdate */, nullptr /* hrgnUpdate */, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
} else {
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, colorkey, 0, LWA_COLORKEY);
transparent = true;
InvalidateRect(hWnd, nullptr, TRUE);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
我不认为分层窗口是每秒打开和关闭多次的(Windows将分配/销毁32 BPP图像等。每次切换时(。p> SWP_FRAMECHANGED
和额外的擦除确实使我至少对我来说更好:
case WM_MOUSEMOVE:
if (transparent) {
transparent = false;
RedrawWindow(hWnd, nullptr /* lprcUpdate */, nullptr /* hrgnUpdate */, RDW_INTERNALPAINT|RDW_INVALIDATE|RDW_ERASE|RDW_ERASENOW|RDW_UPDATENOW|RDW_ALLCHILDREN);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOACTIVATE);
InvalidateRect(hWnd, nullptr, true);
} else {
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, colorkey, 0, LWA_COLORKEY);
SetWindowPos(hWnd, 0, 0, 0, 0, 0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER|SWP_FRAMECHANGED|SWP_NOACTIVATE);
transparent = true;
InvalidateRect(hWnd, nullptr, true);
}
TCHAR b[99];wsprintf(b,TEXT("%d tick=%d"), transparent, GetTickCount()), SetWindowText(hWnd, b);
break;
似乎这些分层的窗口更改需要一些时间才能反映在窗口的渲染中。添加睡眠会使绿色无法显示。
case WM_MOUSEMOVE:
if (transparent) {
transparent = false;
RedrawWindow(hWnd, nullptr /* lprcUpdate */, nullptr /* hrgnUpdate */, RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW | RDW_ALLCHILDREN);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) & ~WS_EX_LAYERED);
}
else {
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, colorkey, 0, LWA_COLORKEY);
Sleep(1); // Add sleep
transparent = true;
InvalidateRect(hWnd, nullptr, TRUE);
}
break;