0

我有一个下拉菜单,我想用它来更改窗口的背景;该窗口默认为我的“冬季背景”。

wClass.hbrBackground = CreatePatternBrush(LoadBitmap(hInst, MAKEINTRESOURCE(WinterBG)));

Whenever an item in the drop-down menu is chosen, it sets off CBN_SELCHANGE, where I grab the length and string of the item chosen. 我希望在此基础上改变背景。

case WM_COMMAND:
    {
        switch(HIWORD(wParam))
        {
        case CBN_SELCHANGE:
            {
                ItemIndex = SendMessage((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
                int ItemLen = SendMessage((HWND)lParam, (UINT)CB_GETLBTEXTLEN, (WPARAM)0, (LPARAM)0);
                char* ListItem = (char*)malloc(ItemLen+1);
                (char)SendMessageA((HWND)lParam, (UINT)CB_GETLBTEXT, (WPARAM)ItemIndex, (LPARAM)ListItem);

                //////////////////////////////////////////////////////////////////////////////////////////////////
                // I am certain this can be optimized

                if ( ItemLen == 5 && ListItem[0] == 'S' ) // Spring
                {
                    MessageBox(NULL, L"Spring chosen", L"Confirmed", MB_ICONINFORMATION | MB_OK);
                    HBRUSH brush = CreatePatternBrush(LoadBitmap(wClass.hInstance, MAKEINTRESOURCE(SpringBG)));
                    SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG)brush);
                    InvalidateRect(hWnd, NULL, TRUE);
                    UpdateWindow(hWnd);
                }
.....

SetClassLongPtr 没有按我想要的方式工作。更新窗口后(我阅读了 InvalidateRect 和 UpdateWindow 来实现),没有任何变化——背景仍然在我的“WinterBG”上。

我正确使用 SetClassLongPtr 吗?如果没有,我还能如何更改背景?

4

1 回答 1

0

我已经尝试过您在一个简单的 Win32 项目中尝试完成的工作,并设法使其工作。要使下面的代码工作,您需要确保两个位图都作为资源存在于您的 VC++ 项目中。我在我的 VC++ 项目中定义了两个位图作为资源。我没有像你那样使用任何菜单。我正在处理 WM_KEYDOWN 消息,但想法是一样的,这也应该在您的 WM_COMMAND 消息下工作。下面的代码做了以下事情:

  1. 从 exe 文件的资源部分加载位图。为此它需要一个 HINSTANCE,在您的 WndProc 中您可以使用 GetWindowLongPtr 获得它(使用它而不是 GetWindowLong,尤其是当您为 64 位环境编码时,另请参阅 Microsoft 在https://docs.microsoft.com中的说明/en-us/windows/win32/api/winuser/nf-winuser-getwindowlongw)。
  2. 使用您使用的相同功能创建新画笔:“CreatePatternBrush”。
  3. 使用此画笔更改窗口的背景并存储返回的旧画笔,以便以后将其删除。您可以使用 SetClassLongPtr 执行此操作(此处适用相同的 64 位注释)。令人困惑的部分可能是最后一个参数,它是 LONG_PTR。这看起来像是一个指向读者的指针,但实际上它是一个 __int64(64 位整数)。
  4. 删除旧画笔(以防止内存泄漏,特别是如果您希望在会话中多次执行此代码)。
  5. 通过使整个客户区(参数 NULL)无效并将 repaint 参数设置为 TRUE 来刷新窗口。

那应该这样做。这是执行此操作的 WndProc 函数部分:

    case WM_KEYDOWN:
    switch (wParam)
    {
    case VK_F1:
        HINSTANCE hInst2 = (HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE);
        HBITMAP newBmp = LoadBitmapW(hInst2, MAKEINTRESOURCE(IDB_BITMAP2));
        HBRUSH newBrush = (HBRUSH)CreatePatternBrush(newBmp);
        HBRUSH oldBrush = (HBRUSH)SetClassLongPtr(hwnd, GCLP_HBRBACKGROUND, (LONG_PTR)newBrush);
        DeleteObject(oldBrush);
        InvalidateRect(hwnd, NULL, TRUE);
        break;
    }
    break;

小备注:上面代码中的最后一个“中断”只是因为在我的 WndProc 的底部调用了 DefWindowProc。在 WndProc 中处理 WM_KEYDOWN 消息时,应始终将其传递给 DefWindowProc,以便 Windows 可以正确处理它。在您的菜单情况下,最后一个“break”语句可能会被“return 0”替换。

于 2019-09-05T14:23:13.947 回答