Код рисования не работает должным образом в моем обработчике сообщений WM_COMMAND

У меня есть следующий код, который должен рисовать picture2.bmp после того, как пользователь вызывает элемент ID_FILE_32771,

case WM_COMMAND:
    wmId    = LOWORD(wParam);
    wmEvent = HIWORD(wParam);
    // Parse the menu selections:
    switch (wmId)
    {
    case ID_FILE_32771:
        hdc = BeginPaint(hWnd, &ps);
        LoadAndBlitBitmap2(__T("D://picture2.bmp"), hdc);
        EndPaint(hWnd, &ps);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    break;
case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);
    LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);
    EndPaint(hWnd, &ps);
    break;

Проблема в том, что ничего не красится. hdc не правильно инициализирован. Что я делаю не так, и как мне это исправить?

3 ответа

Решение

BeginPaint а также EndPaint функции должны вызываться только при обработке WM_PAINT сообщение. То, как вы это сделали, в обработке WM_COMMAND, неправильно:

case ID_FILE_32771:
        hdc = BeginPaint(hWnd, &ps);                        // WRONG, WRONG!
        LoadAndBlitBitmap2(__T("D://picture2.bmp"), hdc);
        EndPaint(hWnd, &ps);                                // ALSO WRONG!
        break;

Весь код рисования должен быть внутри WM_PAINT обработчик. Вы собираетесь получить WM_PAINT сообщения всякий раз, когда ваше окно должно быть нарисовано, а иногда это вне вашего контроля. Так что должна быть логика в WM_PAINT обработчик, который знает, что рисовать на основе текущего состояния приложения.

Другими словами, вам нужно установить флаг в ответ на клики по ID_FILE_32771 чтобы ваша программа знала, что она должна вызывать LoadAndBlitBitmap2 когда он перекрашивается, а не LoadAndBlitBitmap (почему они не являются одной и той же функцией, которой вы просто передаете разные имена файлов?).

Вне WM_PAINT обработчик, вы вызываете событие рисования, делая недействительным содержимое вашего окна. Самый простой и наиболее подходящий способ сделать это - вызвать InvalidateRect функция Например:

case ID_FILE_32771:
        // Set a flag indicating that picture2 should be painted
        // (or some other equivalent mechanism)
        paintPicture2 = true;

        // Signal that the window should be repainted.
        InvalidateRect(hWnd, NULL, TRUE);

        break;

По телефону UpdateWindow после InvalidateRectВы будете вынуждены немедленно перекрасить, но это редко необходимо. Кроме того, вы можете пропустить танец с двумя функциями и вызвать более мощный RedrawWindow функционировать напрямую.

В любом случае, вы будете ссылаться на WM_PAINT обработчик сообщений, и он запросит текущее состояние приложения и нарисует соответствующую картинку.

case WM_PAINT:
    hdc = BeginPaint(hWnd, &ps);

    // Paint the appropriate thing, depending on the app's current state
    if (paintPicture2)
        LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);
    else
        LoadAndBlitBitmap(__T("D://picture.bmp"), hdc);

    EndPaint(hWnd, &ps);
    break;

BeginPaint используется только в WM_PAINT. Вы можете использовать GetDC, если вам нужен HDC вне WM_PAINT. Но лучшее решение обычно заключается в том, чтобы просто вызвать InvalidateRect вне WM_PAINT. Это приведет к появлению нового WM_PAINT в ближайшее время, и вы сделаете все рисование в WM_PAINT.

Из MSDN:

Приложение не должно звонить BeginPaint кроме как в ответ на сообщение WM_PAINT

То есть ваше исправление состоит в том, чтобы использовать API предполагаемым образом, что обычно делает представление недействительным через InvalidateRect а затем рисует WM_PAINT когда вас попросят

Другие вопросы по тегам