0

ウィンドウの背景を変更するために使用したいドロップダウンメニューがあります。ウィンドウはデフォルトで「冬の背景」になっています。

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

ドロップダウンメニューの項目が選択されると、CBN_SELCHANGEが開始され、選択した項目の長さと文字列が取得されます。それに基づいて背景を変えてほしい。

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++ プロジェクトで 2 つのビットマップをリソースとして定義しました。私はあなたのようにメニューを使用していません。私は WM_KEYDOWN メッセージを処理していますが、考え方は同じです。これは WM_COMMAND メッセージの下でも機能するはずです。以下のコードは、次のことを行います。

  1. exe ファイルのリソース セクションからビットマップを読み込みます。これには、WndProc 内で GetWindowLongPtr を使用して取得できる HINSTANCE が必要です (特に 64 ビット環境でコーディングしている場合は、GetWindowLong の代わりにこれを使用してください。https://docs.microsoft.com のこれに関する Microsoft のメモも参照してください)。 /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 メッセージを処理するときは、Windows で正しく処理できるように、常に DefWindowProc に渡す必要があります。メニューの場合、この最後の「break」ステートメントは、おそらく「return 0」に置き換えることができます。

于 2019-09-05T14:23:13.947 に答える