改善WM_PAINT和WM_CTLCOLORSTATIC处理程序的代码

4

介绍和相关信息:

我已经实现了主窗口背景和其子静态控件的复杂绘制。

下面的图片展示了它的外观。

enter image description here

静态控件具有SS_NOTIFY样式,这一点很重要,因为当用户点击它们时会发生某些事情。

此时,单击它们激活的操作并不相关。

主窗口和静态控件都具有渐变背景,这是通过使用GradientFill(...) API实现的。

主窗口的顶部横幅是用灰色画刷创建的,网格线是使用LineTo(...)MoveTo(...) API创建的。

橙色静态控件上的地图和左上角的标志是EMF文件,右上角的标志是PNG文件,其他图片是位图。

橙色静态控件有4个子静态控件,这些控件是owner drawn并且也具有SS_NOTIFY样式。

这是我能想到的唯一方法,它使我能够按照要求绘制控件(如果我能改进这个方法,请建议,我会接受任何合理的建议)。

为了绘制橙色静态控件,我决定在WM_CTLCOLORSTATIC处理程序中绘制其背景,并在子类过程中绘制子静态控件。

从子静态控件接收到的通知也在橙色静态控件的子类过程中处理,因为我不知道如何将它们转发给父窗口,但由于它们此时也不相关,所以被省略了。

我决定提供演示项目的链接,而不是用代码片段让这篇文章变得很长。

我已经尽可能地提交了简单小巧的演示应用程序。

我没有吝啬评论,因此我相信源代码中的所有内容都很好地涵盖和解释了。

如果仍有问题,请留言,我会尽快回复(通常是立即或同一天内回复)。

这是演示项目的链接:http://www.filedropper.com/geotermistgrafika_1

重要更新:

/==========================================================/

方括号中的文本是问题的原始部分,但现在已被省略,因为该项目存在内存泄漏。上面的链接链接到改进版本。

[响应成员xMRi的评论更新:此链接应该没问题:http://www.filedropper.com/geotermistgrafika]

/ ========================================================== /

我使用MS Visual Studio C++和纯Win32 API在Windows XP上工作。

一个注意事项:由于VS Express版没有资源编辑器,因此使用ResEdit从这里创建了资源文件和资源头:http://www.resedit.net/

问题:

当我调整窗口大小时,静态控件会轻微闪烁。

解决问题的努力:

我认为我的代码没有内存泄漏-因此我怀疑这不是问题,但由于缺乏经验,如果可以确认我的假设,我将不胜感激。

我认为我已经正确处理了WM_ERASEBKGND,并且我已经从我的窗口类中排除了样式CS_VREDRAWCS_HREDRAW-因此不应该因此导致闪烁。

我忘记提到,我的窗口具有WS_CLIPCHILDREN样式,因此我在回应成员Roger Rowland的评论下面提到了这一点。

我已经为两个处理程序实现了双缓冲,以避免闪烁。

问题:

  1. 如何修改演示项目中的代码以消除闪烁?

  2. 我需要建议如何优化WM_PAINTWM_CTLCOLORSTATIC处理程序,以使我的绘画代码更有效和更快。

第二个问题的小注释:

我想通过在主窗口的背景上绘制整个图片,并在对应静态控件的背景上放置透明的静态控件来改进我的代码。

那样,我只会在我的WM_CTLCOLORSTATIC处理程序中返回NULL_BRUSH,并在WM_PAINT中完成所有工作。

我的想法正确吗?这可以工作吗?

谢谢。 问候。


演示项目链接已损坏! - xMRi
你的主窗口是否具有WS_CLIPCHILDREN样式? - Roger Rowland
@RogerRowland 是的,它确实有。 - AlwaysLearningNewStuff
@RaymondChen,您能提供简明具体的指导吗?非常感激,因为我目前不知道如何做。谢谢。 - AlwaysLearningNewStuff
简述:在 WM_PAINT 中不做任何事情。所有的工作都在 WM_CTLCOLORSTATIC 中完成,其中你只需要绘制一次屏幕。(将所有内容组合成一个位图,然后使用 BitBlt 将位图复制到屏幕上。) - Raymond Chen
显示剩余2条评论
1个回答

1

首先,你的App漏洞百出。虽然我没有查找漏洞,但它们中的大多数应该在WM_CTLCOLORSTATIC中,因为你忘记删除HBITMAP(使用这个方便的免费软件http://www.nirsoft.net/utils/gdi_handles.html来查找gdi泄漏)。

其次,你的代码太庞大了。我注意到你没有使用函数,可能是因为你不知道它们的能力。例如,我会使用:

void DrawBackground(HDC &hDC, SOMEINFOSTRUCT GradientInfo, LPCTSTR Text);

为了简化你的代码。

无论如何,足够讲解了,让我们回到你的问题。在 WM_CTLCOLORSTATIC 中,你必须返回要绘制背景的画刷。你现在正在手动绘制背景,然后返回 NULL 画刷,程序会在你已经绘制好的背景上进行绘制。而不是自己绘制,让画刷来完成这项工作。 简单地说,使用 CreatePatternBrush() 代替最后一个 Bitblt(),但是你需要注意这个画刷,这里是你应该做的:

HBRUSH TempBrush = NULL; //Create global brush

//Some Code....

case WM_CTLCOLORSTATIC:
    {
        if (TempBrush != NULL)
        {
            DeleteObject(TempBrush);
            TempBrush = NULL;
        }

        //Let's skip to the end....
        GradientFill( MemDC, vertex3, 3, &gTriangle, 1, 
        GRADIENT_FILL_TRIANGLE );

        TempBrush  = CreatePatternBrush(bmp);// these 3 line should be at the 
                                            //end of every if
        DeleteDC(MemDC);      // or put them once outside if's
        DeleteObject(bmp);  // also if you delete HDC first, you don't need to
                            //unselect hbitmap
        }
        return (LRESULT)TempBrush;
    }
    break;

case WM_CLOSE:
        {
            if (TempBrush != NULL)
            {
                DeleteObject(TempBrush);
                TempBrush = NULL;
            }
//.......

我只是想确认一下,在我得到一些结果后,很快会“与你交谈”。再次感谢,问候。 - AlwaysLearningNewStuff
如果可以的話,請上傳您修正/更新後的專案,我會為您添加一些好玩的東西,並嘗試簡化您的程式。除此之外,在“所有gdi”(或類似的)列下,當您啟動消息循環時,應有13個(如果您從資源中加載圖片,則更多)對象。然後它應該增加到,假設24,但當您的程序再次閒置時,它應該返回到先前的數字。我已注意到您的數字只是持續增加,這就是我知道存在gdi洩漏的方法(也在任務管理器中,使用的內存迅速增加)。然後您必須查看其他列和... - FrogTheFrog
确定您问题的原因(例如刷子数量不断增加)。然后继续在C++代码的地狱般追寻正义之旅。如果您更新项目,我将添加回调包装器,使您能够将回调保留在类中,从而允许使用局部函数和变量,因为全局变量在安全性和其他方面都是不良选择。 - FrogTheFrog
该项目是商业性质的,因此无法完整上传。演示项目中的这部分绘画与主项目中的完全相同。希望您可以像原始项目一样使用它。如果您仍然想要帮助,我将不胜感激。谢谢。祝好。 - AlwaysLearningNewStuff
明白,那么你将不得不自己调整我的更改。 - FrogTheFrog
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接