简体   繁体   English

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

[英]WM_PAINT handler doesn't perform as it should, flicker-like effect occurs

INTRODUCTION: 介绍:

I have decided to make a test project in MS Visual Studio 2008, in C++ to test a small program in pure WIN32, regarding painting a bitmap as window's background. 我决定在MS Visual Studio 2008中用C ++创建一个测试项目,以在纯WIN32中测试一个小程序,这涉及将位图绘制为窗口的背景。

PROBLEM: 问题:

Window should have gray brush and a bitmap picture stretched over its client area. 窗口应具有灰色画笔,并在其客户区域上展开位图图片。

In my code for WM_PAINT , if I try to paint gray brush for window, without bitmap, everything seems to work well. WM_PAINT代码中,如果我尝试为没有位图的窗口绘制灰色画笔,那么一切似乎都可以正常工作。

Same goes if I just try to put a bitmap as a background. 如果我只是尝试将位图作为背景,也是如此。

Yet, when I combine these two , so I can get a bitmap picture stretched, and gray background behind bitmap, this is what happens: 但是, 当我将两者结合时 ,可以拉伸位图图片,并在位图后面添加灰色背景,这是发生的情况:

Bitmap picture appears to "stands still", but gray brush appears over entire window for a second, then disappears entirely, so only stretched bitmap is seen, and then appears again, and so on. 位图图片似乎“静止不动”,但是灰色画笔在整个窗口上出现了一秒钟,然后完全消失,因此只能看到拉伸的位图,然后再次出现,依此类推。

It seems as if it is drawn from top going to the bottom, and it seems as if application is doing it all over again. 似乎好像是从上到下绘制的,似乎应用程序又在做一遍。

This is how I see it when I start my program. 这就是我启动程序时看到的样子。

RELEVANT INFORMATION: 相关信息:

The program was made by choosing option File->New, and then choosing Win32 project from the options. 该程序是通过选择选项文件->新建,然后从选项中选择Win32项目制成的。

Window class was set automatically, and the following members were set like this: 窗口类是自动设置的,以下成员的设置如下:

   wcex.style = CS_HREDRAW | CS_VREDRAW;

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

I have added static global variable to store bitmap handle: 我添加了静态全局变量来存储位图句柄:

   static HBITMAP bmp;

In the window procedure, made by the wizard, I have initialized it with following code: 在向导创建的窗口过程中,我已使用以下代码对其进行了初始化:

   case WM_CREATE:

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

        return 0;

        break;

In the window procedure, made by the wizard, I have added WM_PAINT handler, with following code: 在向导创建的窗口过程中,我添加了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;

I have also invalidated client area when window is resized, or erasing of background happens, like this: 调整窗口大小或擦除背景时,我也使客户区域无效,如下所示:

   case WM_ERASEBKGND:

        InvalidateRect( hWnd, NULL, TRUE );

        return 1L;
        break;

   case WM_SIZE:

        InvalidateRect( hWnd, NULL, TRUE );

        return 0L;

Bitmap is destroyed like this: 位图被破坏是这样的:

   case WM_DESTROY:

        DeleteObject( bmp );

        PostQuitMessage(0);
        break;

IMPORTANT NOTE: 重要的提示:

Even if I comment out handlers for WM_SIZE and WM_ERASEBKGND , the effect still occurs. 即使我注释掉WM_SIZEWM_ERASEBKGND处理程序,效果仍然会发生。

I do not have much experience with double buffering, but this is simple thing to do. 我对双重缓冲没有太多经验,但这很简单。

I just fail to see the mistake, so I ask more experienced and skillfull colleagues to help. 我只是看不到错误,所以我要求更多有经验和技术娴熟的同事提供帮助。

If additional source code is required, ask for it and I will post it, but until then I will omit it to keep the question brief. 如果需要其他源代码,请提出要求,我将其发布,但在此之前,我将省略它以使问题简短。

You should not call InvalidateRect in WM_ERASEBKGND . 您不应在WM_ERASEBKGND调用InvalidateRect That's just going to force an endless series of paint cycles. 这将迫使无休止的一系列油漆循环。

The job of WM_ERASEBKGND is to paint the background, and that's all you should ever do. WM_ERASEBKGND的工作是绘制背景,这是您应该做的所有事情。 If your WM_PAINT is going to paint the entire window, then there's no need to paint any background. 如果您的WM_PAINT要绘制整个窗口,则无需绘制任何背景。 In which case, and I think this is your scenario, you should do nothing in WM_ERASEBKGND . 在这种情况下,我认为这是您的情况,您不应在WM_ERASEBKGND执行任何操作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM