gpt4 book ai didi

c++ - WM_EX_TRANSPARENT 不重绘子窗口

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:45:25 26 4
gpt4 key购买 nike

我在某些窗口上使用 WM_EX_TRANSPARENT 窗口样式,试图进行透明的双缓冲。但是,我遇到了一个问题,因为当我在父窗口上执行 InvalidateRect 时,子窗口没有重绘。

迭代子窗口并让它们重新绘制自己是父窗口的责任,还是我做错了?如果是父窗口的责任,我怎样才能让所有的子窗口都在父窗口的无效矩形内?

这是一个完全可编译的示例,它说明了我正在谈论的行为。当您将鼠标移到父窗口上时,您可以看到该按钮消失了。如果您单击该按钮,该按钮会自行重绘,但当您将鼠标移开并返回到父窗口时,该按钮会再次消失。

#include <Windows.h>

LRESULT CALLBACK WndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
return 0;

case WM_MOUSEMOVE:
InvalidateRect(window, NULL, true);

return 0;

case WM_NCDESTROY:
PostQuitMessage(0);
break;
}

return DefWindowProc(window, uMsg, wParam, lParam);
}

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd) {
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "test_window";

RegisterClass(&wc);

HWND wnd = CreateWindowEx(WS_EX_TRANSPARENT, "test_window", "test", WS_CLIPCHILDREN | WS_OVERLAPPEDWINDOW, 50, 50, 400, 400, NULL, NULL, hinst, NULL);

ShowWindow(wnd, SW_SHOW);

HWND btn = CreateWindowEx(WS_EX_TRANSPARENT, "BUTTON", "button 1", WS_CHILD, 50, 50, 100, 50, wnd, NULL, hinst, NULL);

ShowWindow(btn, SW_SHOW);

MSG m;

while (GetMessage(&m, NULL, 0, 0)) {
TranslateMessage(&m);
DispatchMessage(&m);
}

return 0;
}

最终解决方案

是按照下面建议的答案去做,然后在父窗口的 WM_PAINT 消息中向每个子窗口发送一个 WM_PAINT 并让子窗口绘制到父窗口的双缓冲区中(不向自身绘制任何东西),然后让父级 BitBlt 将其作为缓冲区(已被自身绘制,然后由其每个子项从 Z 顺序的底部到顶部绘制)到它是 HDC。这允许在父项和子项中进行无闪烁绘图,并为子项提供透明度。这是我们得到的最终演示程序:

#include <Windows.h>

// the handle to the single child window
HWND child;

// parent's backbuffer so we can use it in the child
HDC bbuf = 0;

LRESULT CALLBACK WndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
return 0;

case WM_MOUSEMOVE:
InvalidateRect(window, NULL, true);

return 0;

case WM_PAINT: {
PAINTSTRUCT ps;
POINT mpos;
GetCursorPos(&mpos);
ScreenToClient(window, &mpos);

BeginPaint(window, &ps);

// create the backbuffer once
bbuf = bbuf ? bbuf : CreateCompatibleDC(ps.hdc);

// hardcoded size is the same in the CreateWindowEx call
static auto backbmp = CreateCompatibleBitmap(ps.hdc, 400, 400);

static auto unused = SelectObject(bbuf, backbmp);

POINT points[2] = {
{ 0, 0 },
{ mpos.x, mpos.y }
};

// painting into bbuf
// give ourselves a white background so we can see the wblack line
SelectObject(bbuf, (HBRUSH)GetStockObject(WHITE_BRUSH));
Rectangle(bbuf, 0, 0, 400, 400);
SelectObject(bbuf, (HBRUSH)GetStockObject(BLACK_BRUSH));
Polyline(bbuf, points, 2);

// get the child to paint itself into our bbuf
SendMessage(child, WM_PAINT, 0, 0);

// and after the child has drawn, bitblt everything onto the screen
BitBlt(ps.hdc, 0, 0, 400, 400, bbuf, 0, 0, SRCCOPY);

EndPaint(window, &ps);

return 0;
}

case WM_ERASEBKGND:
return 0;

case WM_NCDESTROY:
PostQuitMessage(0);
break;
}

return DefWindowProc(window, uMsg, wParam, lParam);
}

LRESULT CALLBACK ChildWndProc(HWND window, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_CREATE:
return 0;

case WM_PAINT: {
PAINTSTRUCT ps;

BeginPaint(window, &ps);

static auto backbuffer = CreateCompatibleDC(ps.hdc);
static auto backbmp = CreateCompatibleBitmap(ps.hdc, 100, 50);

static auto unused = SelectObject(backbuffer, backbmp);

// copy the parent's stuff into our backbuffer (the parent has already drawn)
BitBlt(backbuffer, 0, 0, 100, 50, bbuf, 50, 150, SRCCOPY);

RECT r = { 0, 0, 50, 100 };

// draw into our backbuffer
SetBkMode(backbuffer, TRANSPARENT);
SetTextColor(backbuffer, RGB(255, 0, 0));
DrawText(backbuffer, "hello", 5, &r, DT_NOCLIP | DT_TABSTOP | DT_EXPANDTABS | DT_NOPREFIX);

// bitblt our stuff into the parent's backbuffer
BitBlt(bbuf, 50, 150, 100, 50, backbuffer, 0, 0, SRCCOPY);

EndPaint(window, &ps);

return 0;
}

case WM_ERASEBKGND:
return 0;
}

return DefWindowProc(window, uMsg, wParam, lParam);
}

int PASCAL WinMain(HINSTANCE hinst, HINSTANCE, LPSTR, int nShowCmd) {
WNDCLASS wc;
wc.style = 0;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "test_window";

RegisterClass(&wc);

wc.style = 0;
wc.lpfnWndProc = ChildWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hinst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = "transparent_window";

RegisterClass(&wc);

HWND wnd = CreateWindowEx(NULL, "test_window", "test", WS_OVERLAPPEDWINDOW | WS_VISIBLE, 50, 50, 400, 400, NULL, NULL, hinst, NULL);

child = CreateWindowEx(NULL, "transparent_window", "", WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CHILD, 50, 150, 100, 50, wnd, NULL, hinst, NULL);

MSG m;

while (GetMessage(&m, NULL, 0, 0)) {
TranslateMessage(&m);
DispatchMessage(&m);
}

return 0;
}

再次感谢 johnathon 花这么多时间帮助我解决这个问题。

最佳答案

从您的父窗口窗口样式中删除 WS_CLIPCHILDREN。这将允许父窗口在子窗口的不动产上进行绘制,然后子窗口将在其绘制调用期间有效地在其上进行绘制。首先调用父窗口的绘制,然后调用任何子窗口的绘制。祝塞斯好运!

关于c++ - WM_EX_TRANSPARENT 不重绘子窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10586410/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com