c++ - WM_PAINT 处理程序未按预期执行,出现类似闪烁的效果

标签 c++ winapi

简介:

我决定在 MS Visual Studio 2008 中用 C++ 做一个测试项目来测试纯 WIN32 中的一个小程序,关于绘制位图作为窗口背景。

问题:

窗口应该有灰色画笔和在其客户区拉伸(stretch)的位图图片。

在我的 WM_PAINT 代码中,如果我尝试在没有位图的情况下为窗口绘制灰色画笔,一切似乎都运行良好。

如果我只是尝试将位图作为背景,情况也是如此。

然而,当我将这两者结合起来时,我可以得到拉伸(stretch)的位图图片,以及位图后面的灰色背景,这就是发生的事情:

位图图片看起来“静止不动”,但灰色画笔出现在整个窗口上一秒钟,然后完全消失,因此只能看到拉伸(stretch)的位图,然后再次出现,依此类推。

看起来好像是从上到下画的,又好像是应用程序从头再来一遍。

这就是我在开始我的程序时看到的。

相关信息:

程序是通过选择选项文件->新建,然后从选项中选择Win32项目来制作的。

窗口类是自动设置的,下面的成员是这样设置的:

   wcex.style = CS_HREDRAW | CS_VREDRAW;

   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

我添加了静态全局变量来存储位图句柄:

   static HBITMAP bmp;

在向导制作的窗口过程中,我用下面的代码初始化了它:

   case WM_CREATE:

        bmp = LoadBitmap( hInst, MAKEINTRESOURCE(IDB_BITMAP1) );

        return 0;

        break;

在向导创建的窗口过程中,我添加了WM_PAINT处理程序,代码如下:

    case WM_PAINT:
     {

        hdc = BeginPaint(hWnd, &ps);

        RECT r;

        GetClientRect( hWnd, &r );

        // TODO: Add any drawing code here...

            // fill client area with gray brush, just to test

            FillRect( hdc, &r, (HBRUSH)GetStockObject( GRAY_BRUSH ) );

            // memory DC for double buffering

        HDC MemDC = CreateCompatibleDC( hdc );

            // select our bitmap into memory DC

        HBITMAP old = (HBITMAP)SelectObject( MemDC, bmp );

            // get bitmap's width and height so we can stretch it  

        BITMAP b;

        GetObject( bmp, sizeof(BITMAP), &b );

            // stretch our bitmap

        StretchBlt( hdc, 0, 0, r.right - r.left, r.bottom - r.top, 
             MemDC, 0, 0, b.bmWidth, b.bmHeight, SRCCOPY );

            // perform proper cleanup

        SelectObject( MemDC, old );

        DeleteDC(MemDC);


        EndPaint(hWnd, &ps);

     }
     return 0L;
     break;

当调整窗口大小时,或者删除背景发生时,我也使客户区无效,如下所示:

   case WM_ERASEBKGND:

        InvalidateRect( hWnd, NULL, TRUE );

        return 1L;
        break;

   case WM_SIZE:

        InvalidateRect( hWnd, NULL, TRUE );

        return 0L;

位图是这样销毁的:

   case WM_DESTROY:

        DeleteObject( bmp );

        PostQuitMessage(0);
        break;

重要提示:

即使我注释掉 WM_SIZEWM_ERASEBKGND 的处理程序,效果仍然存在。

我对双缓冲没有太多经验,但这很简单。

我就是看不出错误,所以请更有经验和技术的同事帮忙。

如果需要额外的源代码,请索取,我会发布,但在此之前我会省略它以保持问题简短。

最佳答案

您不应在 WM_ERASEBKGND 中调用 InvalidateRect。这只会迫使一系列无休止的油漆周期。

WM_ERASEBKGND 的工作是绘制背景,而这正是您应该做的。如果您的 WM_PAINT 将绘制整个窗口,则无需绘制任何背景。在这种情况下,我认为这就是您的情况,您不应该在 WM_ERASEBKGND 中执行任何操作。

关于c++ - WM_PAINT 处理程序未按预期执行,出现类似闪烁的效果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18944246/

相关文章:

c++ - 如何检查两个矩阵是否相同?

c++ - 自Windows 10 20H1起,多个具有单独线程的窗口停止工作

c++ - VirtualAllocEx 成功返回一个基地址,但是 WriteProcess 失败,错误是 487

windows - 如何部署商业可移植应用程序?

c++ - 如何获得 "bus error"?

c++ - 恢复调试 session 不构建更改 VS2012

windows - 检测网络共享的 SMB 与 SMB2

c++ - 无法检测 Windows 字体大小何时更改 C++ MFC

c++ - 如何将字符串数组存储在 vector 中

c++ - 从二叉搜索树中删除只有一个子节点的节点