【问题标题】:Unable to update window in consol application无法更新控制台应用程序中的窗口
【发布时间】:2019-12-03 19:17:35
【问题描述】:

我正在扩展一个旧的控制台应用程序。尝试添加一个窗口(用于动画)。能够显示第一张图像,但无法用后面的图像更新窗口。已创建一个最小应用程序来演示该问题。在这个应用程序中,我有一个红色窗口,每次更新窗口时都会发生变化(它不是)。我做错了什么?

#include "pch.h"
#include <iostream>
#include <Windows.h>

using namespace std;

HWND hWindow;   

LRESULT __stdcall MyWindowProcedure(HWND hWnd, unsigned int msg, WPARAM wp, LPARAM lp)
{
    PAINTSTRUCT ps;
    HDC hdc;
    HBITMAP hBitmap;
    VOID * pvBits;
    RGBQUAD  *bmiColors;
    static int j = 128;
    HBITMAP hOldBmp;
    BITMAPINFO MyBitmap;
    BOOL qRetBlit;


    switch (msg)
    {

    case WM_DESTROY:
        std::cout << "\ndestroying window\n";
        PostQuitMessage(0);
        return 0L;

    case WM_LBUTTONDOWN:
        std::cout << "\nmouse left button down at (" << LOWORD(lp)
            << ',' << HIWORD(lp) << ")\n";
        // fall thru

    case WM_PAINT:

        hdc = BeginPaint(hWnd, &ps);
#if 1
        // Create a device context that is compatible with the window
        HDC hLocalDC;
        hLocalDC = ::CreateCompatibleDC(hdc);
        // Verify that the device context was created
        if (hLocalDC == NULL) {
            printf("CreateCompatibleDC Failed\n");
            //          return false;
            break;
        }

        MyBitmap.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
        MyBitmap.bmiHeader.biWidth = 256;
        MyBitmap.bmiHeader.biHeight = -256;
        MyBitmap.bmiHeader.biPlanes = 1;
        MyBitmap.bmiHeader.biBitCount = 32;
        MyBitmap.bmiHeader.biCompression = BI_RGB;
        MyBitmap.bmiHeader.biSizeImage = 256 * 256 * 4;
        MyBitmap.bmiHeader.biYPelsPerMeter = 1000;
        MyBitmap.bmiHeader.biXPelsPerMeter = 1000;
        MyBitmap.bmiHeader.biClrUsed = 0;
        MyBitmap.bmiHeader.biClrImportant = 0;

        hBitmap = CreateDIBSection(NULL, &MyBitmap, DIB_RGB_COLORS, &pvBits, NULL, NULL);
        bmiColors = (RGBQUAD*)pvBits;

        // note: BGR
        for (int i = 0; i < 256 * 256; i++)
        {
            bmiColors[i].rgbBlue = 0;
            bmiColors[i].rgbGreen = 0;
            bmiColors[i].rgbRed = j % 256;
            bmiColors[i].rgbReserved = 255;
        }
        j += 10;

        bmiColors[1000].rgbRed;

        // Select the bitmap into the device context
        hOldBmp = (HBITMAP)::SelectObject(hLocalDC, hBitmap);
        if (hOldBmp == NULL) {
            printf("SelectObject Failed");
            //          return false;
            break;
        }

        // Blit the dc which holds the bitmap onto the window's dc
        qRetBlit = ::BitBlt(hdc, 0, 0, 256, 256, hLocalDC, 0, 0, SRCCOPY);
        if (!qRetBlit) {
            printf("Blit Failed");
            //          return false;
            break;
        }

        // Unitialize and deallocate resources
        SelectObject(hLocalDC, hOldBmp);
        DeleteDC(hLocalDC);
        DeleteObject(hBitmap);
#endif
        EndPaint(hWnd, &ps);
        break;

    default:

        std::cout << '.';
        break;
    }
    return DefWindowProc(hWnd, msg, wp, lp);
}

int main()

{
    WNDCLASSEX wndclass = { sizeof(WNDCLASSEX), CS_DBLCLKS | CS_HREDRAW, MyWindowProcedure,
                                0,  0, GetModuleHandle(0), LoadIcon(0,IDI_APPLICATION),
                                LoadCursor(0,IDC_ARROW), HBRUSH(COLOR_WINDOW + 1),
                                0, L"myclass", LoadIcon(0,IDI_APPLICATION) };

    if (RegisterClassEx(&wndclass))
    {
        hWindow = CreateWindowEx(0, L"myclass", L"myclass", WS_OVERLAPPEDWINDOW, 1200, 600, 256 + 15, 256 + 38, 0, 0, GetModuleHandle(0), 0);

        ShowWindow(hWindow, SW_SHOWDEFAULT);
        UpdateWindow(hWindow);

        MSG msg;
        byte bRet;

        while ((bRet = GetMessage(&msg, hWindow, 0, 0)) != 0)
        {
            if (bRet == -1)
            {
                return 1;
            }
            else
            {
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
        }
    }
}

【问题讨论】:

  • 您不应调用BeginPaint,除非是为了响应WM_PAINT 消息,并且每次调用BeginPaint 都必须与调用EndPaint 匹配。
  • 所以错误出现在 WM_LBUTTONDOWN 的“缺失”中断中:std::cout
  • 所以 BeginPaint() 和 EndPaint();只能作为对 WM_PAINT 的回应:对吗?
  • BeginPaint 的文档是这么说的。
  • 好吧,这似乎是问题所在。然后我必须通过其他方式更新图像,而不是 WM_LBUTTONDOWN 上的“通过”顺便说一句:我在网上的一些示例中找到了该代码。我将尝试再次找到该示例并添加对此的评论。

标签: c++ animation winapi


【解决方案1】:

正如所指出的。您不想自己调用 WM_PAINT。让系统来处理。所以在 WM_LBUTTONDOWN 做:

case WM_LBUTTONDOWN:
        std::cout << "\nmouse left button down at (" << LOWORD(lp)
            << ',' << HIWORD(lp) << ")\n";
        InvalidateRect(hWnd, nullptr, FALSE);
        return 0;

不要跌倒。 Wnen 你调用RedrawWindow 窗口无效,然后需要重新绘制。我刚刚对此进行了测试,每次单击时窗口都会亮起。

更新: 感谢雷米·勒博

Difference between InvalidateRect and RedrawWindow

是的,最好让 Windows 使用自己的时间表来处理这类事情。

【讨论】:

  • 除非您需要立即重绘,否则您通常应该改用InvalidateRect(),并让操作系统在适当的时候自行生成WM_PAINT
  • @Remy Lebeau,谢谢。我使用 MFC,很少使用控制台方法。我没有为此找到Invalidate()。我会更新我的帖子。
猜你喜欢
  • 2019-01-18
  • 2011-04-20
  • 2014-02-17
  • 1970-01-01
  • 1970-01-01
  • 2011-12-24
  • 2016-03-30
  • 2011-04-04
  • 1970-01-01
相关资源
最近更新 更多