没有经验的win32开发人员询问有关优化/改进WM_PAINT和WM_CTLCOLORSTATIC处理程序代码的建议/说明 [英] Inexperienced win32 developer asks advice/instructions for optimizing/improving code for WM_PAINT and WM_CTLCOLORSTATIC handlers

查看:71
本文介绍了没有经验的win32开发人员询问有关优化/改进WM_PAINT和WM_CTLCOLORSTATIC处理程序代码的建议/说明的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

介绍及相关信息:



我已经实现了主窗口背景的复杂绘画及其儿童静态控件。



此图片的链接显示了它的外观: http:// pbrd.co/1cx8DHd [ ^ ]



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



此时,点击它们时激活的操作无关紧要。



主窗口和静态控件都有渐变背景,通过使用 GradientFill(...) API制作。



顶部横幅使用灰色画笔创建主窗口,并使用 LineTo(...) MoveTo(...) API。



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



橙色静态控件有4个子静态控件,是业主绘制的,还有 SS_NOTIFY 样式。



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



为了绘制橙色静态控件,我决定在 WM_CTLCOLORSTATIC
处理程序,并在所有者中绘制子类过程中的子静态控件。



从子静态控件接收的通知也在orange static控制子类程序,因为我不知道如何将它们转发到父窗口,但由于它们此时也无关紧要而被省略。



我决定提供演示项目的链接,而不是使用代码片段使这篇文章相当冗长。



我试图尽可能小而简单地提交演示应用程序。



我没有吝啬评论,所以我相信一切都很好在源代码中解释。



如果还有问题请发表评论我会尽快回复(通常是立即,或者在同一天,至少)。



以下是演示项目的链接: http://www.filedropper .com / geotermistgrafika_1 [ ^ ]



http://www.uploadmb.com/dw.php ?id = 1383366869 [ ^ ]



如果你有下载问题,只需点击下面的点击此处立即下载文件,一切都会好的。



添加了额外的链接,因为原来的链接不时被破坏:

http://www.filedropper.com/geotermistgrafika [ ^ ]

[以上项目有内存泄漏,新链接链接到改进版本]




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



一个注意事项:因为VS 的Express版本没有资源编辑器,资源文件和资源头是使用 ResEdit 从这里创建的: http://www.resedit .net / [ ^ ]



问题:




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



我解决问题的努力:



我相信我的代码没有内存泄漏 - 因此我怀疑这是问题所在,但由于缺乏经验,如果我的假设可以某种方式得到确认,我将非常感激。



我认为我已正确处理 WM_ERASEBKGND , d我从我的窗口类中排除了 CS_VREDRAW CS_HREDRAW 的样式 - 因此不应该因此引起闪烁。< br $>


我的窗口有 WS_CLIPCHILDREN 样式。



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



问题:



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



2.我需要建议关于如何优化 WM_PAINT WM_CTLCOLORSTATIC 处理程序,以便我的绘画代码更有效,更快。



第二个问题的小注释:




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



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



我有这个想法吗?



谢谢。



问候。

INTRODUCTION AND RELEVANT INFORMATION:

I have implemented complex painting of the main window’s background and its child static controls.

The link to this picture shows how it looks:http://pbrd.co/1cx8DHd[^]

Static controls have SS_NOTIFY style, which is important to mention, as certain things happen when user clicks on them.

At this point, actions activated when clicking on them, are not relevant.

Both main window, and static controls, have gradient backgrounds, which were made through usage of GradientFill(...) API.

Top banner of the main window is created with gray brush, and the grid lines were created with LineTo(...) and MoveTo(...) API.

Map on the orange static control, and the top left logo are EMF files, top right logo is PNG file, and other pictures are bitmaps.

Orange static control has 4 child static controls which are owner drawn and also have SS_NOTIFY style.

It was the only way I could have thought of, which enabled me to draw the control the way it was asked of me ( if I can improve on this, please suggest it, I will accept any reasonable suggestion ).

In order to paint the orange static control, I have decided to paint its background in WM_CTLCOLORSTATIC handler, and to owner draw child static controls in a subclass procedure.

Notifications received from child static controls are also handled in the orange static controls subclass procedure, since I didn’t know how to forward them to the parent window, but are omitted since they are also irrelevant at this moment.

I have decided to provide link to the demo project, instead of making this post quite lengthy with code snippets.

I have tried to submit demo application as small and simple as it is possible.

I did not skimp on the commentaries, so I believe everything is well covered and explained in source code.

If there are still questions please leave a comment and I will reply as soon as possible ( usually immediately, or in the same day, at least ).

Here is the link to the demo project: http://www.filedropper.com/geotermistgrafika_1[^]

http://www.uploadmb.com/dw.php?id=1383366869[^]

If you have problem with the download, just click bellow on the click here to Download the file now and everything will be fine.

Added additional link since the original one becomes broken from time to time:
http://www.filedropper.com/geotermistgrafika[^]

[The above project had memory leaks, the new link links to the improved version]


I work on Windows XP, using MS Visual Studio C++ and pure Win32 API.

One note: since Express edition of VS has no resource editor, resource file and resource header were created using ResEdit from here: http://www.resedit.net/[^]

PROBLEM:


When I resize my window, static controls slightly flicker.

MY EFFORTS TO SOLVE PROBLEM:

I believe that my code has no memory leaks-therefore I doubt this is the problem, but being inexperienced, I would highly appreciate if my assumption can be somehow confirmed.

I think that I have properly handled WM_ERASEBKGND, and I have excluded styles CS_VREDRAW and CS_HREDRAW from my window class-therefore flickering should not be caused because of this.

My window has WS_CLIPCHILDREN style.

I have implemented double buffering for both handlers, in order to avoid flickering.

QUESTIONS:

1. How can I modify code in demo project to get rid of flickering?

2. I need advice on how to optimize both WM_PAINT and WM_CTLCOLORSTATIC handlers, so my painting code gets more efficient and faster.

A small note for second question:


I was thinking to improve my code by drawing the entire picture on the main window’s background, and to put transparent static controls on top of the part of the picture that corresponds that static controls background.

That way, I would only return NULL_BRUSH in my WM_CTLCOLORSTATIC handler, and do all the work in the WM_PAINT.

Am I on the right track with this idea?

Thank you.

Regards.

推荐答案

好的,那么从哪里开始?



我从一系列角度看待这个问题,我一定在思考并尝试了几十种方法组合,但我想我找到了一个可行的方法。 />


基本上,我们的想法是在对话框/窗口本身上完成所有绘图,然后使用不可见的按钮控件,以简化鼠标/键盘消息的处理。实际上,我刚刚只考虑了键盘消息 - 如果你想能够使用键盘浏览窗口上的各种控件,你真的需要提供某种状态的视觉指示 - 无论是焦点,悬停或活跃。明白我的代码没有考虑到这一点,虽然它可以很容易地进行调整..



首先,我尝试使用3个按钮绘制橙色方块映射到memDC并通过子类静态hdc进行爆破。这工作没问题 - 地图的绘图中不再有任何闪烁或问题 - 问题是有一个短暂的时刻,主窗口的背景是可见的橙色方块应该是。



我也意识到窗口允许你将这么多数据附加到窗口本身的方式非常方便,它大大简化了代码,因为每个函数都可以用通用的方式编写在重复使用不同的输入数据之前的方式。这导致我将蓝色按钮包装成c ++类。这是一种非常类似于mfc / win32 ++ / wxWidgets / Qt的方法 - 这使得将窗口文本,字体和图像干净地附加到蓝色按钮变得非常容易。它还有助于简化数据在源代码中的存储方式。问题是虽然仍然存在可怕的闪烁 - 在绘制对话框背景和绘制所有控件的时间之间发生闪烁。



嗯。



然后我辞职了,自定义绘制整个界面作为主窗口的背景+寻找我可以处理鼠标消息的旧代码。 br />


然后我有了一个想法..



我不能只是将一些按钮控件子类化并且在WindowProc,只是将所有内容传递给默认窗口proc除了绘图代码?这不是我想要的吗?



所以,我做到了这一点。为每个按钮所需的数据创建一个简单的结构,每当窗口移动时更新每个按钮的位置。在绘制窗口时,我在计算的位置绘制按钮并将隐形按钮移动到相同的位置。因此,使用一些代码来移动控件以及更多的代码来继承原始的WndProc,我们已经不再需要进行脏的,低级别的鼠标操作。您可能希望通过直接绘制到窗口hdc来处理按钮的鼠标事件,而不是(全尺寸)屏幕外的事件。如果这还不够快,你可以创建一个与按钮大小相同的memDC,在BitBlt到屏幕之前,将按钮的状态改变(悬停,激活,聚焦)到此DC。



我已经(过度)简化了一些事情,只是掀起了一个简短的样本,我希望这样可以指向更好的方向。



请记住,我编写的代码要清晰简单,而不是高效。改进当然包括

例如

加载EMF文件一次

只在窗口大小改变时创建memDC和memBmp





我建议您使用地图对橙色面板上的按钮执行相同的操作。也就是说,编写一个函数,在指定的hdc上使用指定的图像和文本绘制一个覆盖指定rect的按钮。保持每个人的位置,当你重新调整窗口大小时更新它,将隐形按钮重新定位在相同的位置,完成!



最后(哇!我注意到窗口可以让我变得如此之小以至于界面变得非常丑陋,一些元素与其他元素重叠。在这种情况下,您可能希望查看WM_GETMINMAXINFO消息。通过这样做,您可以告诉窗口用户可以创建窗口的最大和最小尺寸。我已经处理了这个消息,使用了避免这种情况的大小。



所以,代码!



resource.rc

Okay then, well where to begin?

I looked at this problem from a bunch of angles, I must've pondered and tried 1/2 a dozen combinations of approaches, but I think I've found one that is workable.

Basically, the idea is to do all the drawing on the dialog/window itself and then use button controls that are invisble, to simplify the handling of mouse/keyboard messages. Actually, I've only just considered keyboard messages just now - if you want to be able to navigate through the various controls on the window using the keyboard, you really need to provide some kind of visual indication of state - whether it be focus, hover or active. Understand that my code hasn't taken this into consideration, though it could easily be adapted..

First, I tried drawing the orange square with the 3 buttons and the map into a memDC and blasting that to screen via a subclassed static's hdc. This worked okay - there was no longer any flicker or problem in the drawing of the map - the problem though was that there was a brief moment when the main window's background was visible where the orange square should be.

I also realized that the way that windows can allow you to attach so many pieces of data to the window itself is really convenient and it simplifies the code greatly, since each function can be written in a generic way before being re-used with differing input data. This caused me to wrap the blue buttons into a c++ class. This being an approach quite similar to mfc/win32++/wxWidgets/Qt - this made it very easy to cleanly attach the window text, font and image to the blue buttons. It also helps simplyfy the way the data is stored in the source code. Problem was though there was still the dreaded flicker - flicker that occurs between the time the dialog background has been drawn and the time that all of the controls have been drawn.

Hmm.

So then I resigned myself to custom-drawing the whole interface as the main window's background + looking for old code I had that would handle the mouse messages.

But then I had an idea..

Couldn't I just subclass some button controls and in the WindowProc, just pass everything to the default window proc except for the drawing code? Wouldn't that do what I want?

So, I did just that. Made a simple struct for the data each button would need, updating the position of each whenever the window is moved. When it comes time to paint the window, I draw buttons at the calculated positions and move the invisible buttons to the same position. So with a few iines of code to move the controls and a few more to subclass the original WndProc, we've done away with the need to do dirty, lowish-level mouse-work. You may wish to handle mouse-events for the buttons by drawing directly to the window hdc, rather than the (full-size) off-screen one. If this wasn't quite quick enough, you could create a memDC the size of the button, draw the button with it's altered state (hover, active, focus) to this DC, before BitBlt to the screen.

I've (over)simplified a few things and just whipped up a 'short' sample that I hope will point you in a better direction.

Bear in mind, I've written the code to be clear and simple, rather than efficient. Improvements would certainly include
e.g
load EMF file just once
only create memDC and memBmp when window size changes


I suggest you just do the same trick for the 'buttons' on the orange panel with the map. That is, write a function that will draw a button covering a specified rect, on a specified hdc, with specified image and text. Keep the position of each one somewhere, update it when you re-size the window, re-position the invisible buttons in same positions, done!

Lastly (whew!) I noticed that the window could me made so small that the interface became very ugly, with some elements overlapping others. In this case, you may wish to look at the WM_GETMINMAXINFO message. By doing so, you can tell window the largest and smallest size the window can be made by the user. I've handled that message, using the size that avoided this.

So, the code!

resource.rc
// Generated by ResEdit 1.5.11
// Copyright (C) 2006-2012
// http://www.resedit.net
#include <windows.h>
#include <commctrl.h>
#include <richedit.h>
#include "resource.h"

//
// Dialog resources
//
LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
DLG_MAIN DIALOG 0, 0, 186, 95
STYLE DS_3DLOOK | DS_CENTER | DS_SHELLFONT | WS_CAPTION | WS_VISIBLE | WS_POPUP | WS_THICKFRAME | WS_SYSMENU
EXSTYLE WS_EX_WINDOWEDGE
CAPTION "Dialog"
FONT 8, "Ms Shell Dlg"
{
}





resource.h



resource.h

#ifndef IDC_STATIC
#define IDC_STATIC (-1)
#endif

#define DLG_MAIN                                100







main.cpp




main.cpp

#define UNICODE
#define WINVER 0x0500

#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <gdiplus.h>
#include "resource.h"

#define firstBigBtnId 5000

using namespace Gdiplus;

HINSTANCE hInst;
WNDPROC oldBtnProc;

typedef struct
{
    wchar_t *text;
    RECT rect;
    HBITMAP img;
}  bigBtn_t, *pBigBtn_t;

bigBtn_t bigBtns[4] =
 {
     { L"УНОС ПОДАТАКА" },
     { L"ПРЕГЛЕД ПОДАТАКА" },
     { L"ИЗВЕШТАЈ" },
     { L"ПРЕТРАГА" }
 };

void GradientFillTriangle(HDC hdc, POINT p1, POINT p2, POINT p3, COLORREF col1, COLORREF col2, COLORREF col3)
{
    TRIVERTEX vertex[3];
    GRADIENT_TRIANGLE gTri = {0,1,2};

    vertex[0].x = p1.x;
    vertex[0].y = p1.y;
    vertex[0].Red = GetRValue(col1) << 8;
    vertex[0].Green = GetGValue(col1) << 8;
    vertex[0].Blue = GetBValue(col1) << 8;
    vertex[0].Alpha = 255;

    vertex[1].x = p2.x;
    vertex[1].y = p2.y;
    vertex[1].Red = GetRValue(col2) << 8;
    vertex[1].Green = GetGValue(col2) << 8;
    vertex[1].Blue = GetBValue(col2) << 8;
    vertex[1].Alpha = 255;

    vertex[2].x = p3.x;
    vertex[2].y = p3.y;
    vertex[2].Red = GetRValue(col3) << 8;
    vertex[2].Green = GetGValue(col3) << 8;
    vertex[2].Blue = GetBValue(col3) << 8;
    vertex[2].Alpha = 255;

    GradientFill(hdc, vertex, 3, &gTri, 1, GRADIENT_FILL_TRIANGLE );
}

void squareRadialFillRect(HDC hdc, RECT fillMe, COLORREF colInner, COLORREF colOuter)
{
    POINT p1, p2, p3;
    p3.x = fillMe.left + (fillMe.right - fillMe.left) / 2;
    p3.y = fillMe.top + (fillMe.bottom - fillMe.top) / 2;

    p1.x = fillMe.left;     p1.y = fillMe.top;
    p2.x = fillMe.right;    p2.y = fillMe.top;
    GradientFillTriangle(hdc, p1,p2,p3, colOuter, colOuter, colInner);

    p1 = p2;
    p2.x = fillMe.right;
    p2.y = fillMe.bottom;
    GradientFillTriangle(hdc, p1,p2,p3, colOuter, colOuter, colInner);

    p1 = p2;
    p2.x = fillMe.left;
    p2.y = fillMe.bottom;
    GradientFillTriangle(hdc, p1,p2,p3, colOuter, colOuter, colInner);

    p1 = p2;
    p2.x = fillMe.left;
    p2.y = fillMe.top;
    GradientFillTriangle(hdc, p1,p2,p3, colOuter, colOuter, colInner);
}

void diagGradFillRect(HDC hdc, RECT fillMe, COLORREF colDiag, COLORREF colCorners, bool isDiagLeftToRight)
{
    POINT p1,p2,p3;
    if (isDiagLeftToRight == true)
    {
        p1.x = fillMe.left;
        p1.y = fillMe.top;

        p2.x = fillMe.right;
        p2.y = fillMe.bottom;

        p3.x = fillMe.right;
        p3.y = fillMe.top;
        GradientFillTriangle(hdc, p1,p2,p3,colDiag,colDiag,colCorners);

        p3.x = fillMe.left;
        p3.y = fillMe.bottom;
        GradientFillTriangle(hdc, p1,p2,p3,colDiag,colDiag,colCorners);
    }
}

void GradientFillRect(HDC hdc, RECT fillMe, COLORREF colStart, COLORREF colEnd, bool isVertical)
{
    TRIVERTEX vertex[2];
    GRADIENT_RECT gRect;
    gRect.UpperLeft = 0;
    gRect.LowerRight = 1;
    vertex[0].x = fillMe.left;
    vertex[0].y = fillMe.top;
    vertex[0].Red = GetRValue(colStart) << 8;
    vertex[0].Green = GetGValue(colStart) << 8;
    vertex[0].Blue = GetBValue(colStart) << 8;
    vertex[0].Alpha = 255;

    vertex[1].x = fillMe.right;
    vertex[1].y = fillMe.bottom;
    vertex[1].Red = GetRValue(colEnd) << 8;
    vertex[1].Green = GetGValue(colEnd) << 8;
    vertex[1].Blue = GetBValue(colEnd) << 8;
    vertex[1].Alpha = 255;

    if (isVertical)
        GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_V );
    else
        GradientFill(hdc, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H );
}

void drawBigBtn(HDC dst, RECT btnRect, wchar_t *wndText)
{
    RECT topRect, botRect;
    topRect = botRect = btnRect;
    topRect.bottom = botRect.top = ((btnRect.bottom - btnRect.top)/2) + btnRect.top;
    GradientFillRect(dst, topRect, RGB(0x95,0xb3,0xd7), RGB(0x4f,0x8b,0xb0), true);
    GradientFillRect(dst, botRect, RGB(0x4f,0x8b,0xb0), RGB(0x95,0xb3,0xd7), true);

    HBRUSH blueBrush, oldBrush;
    blueBrush = CreateSolidBrush(RGB(79,129,189));
    oldBrush = (HBRUSH) SelectObject(dst, blueBrush);
    FrameRect(dst, &btnRect, blueBrush);
    SelectObject(dst, oldBrush);
    DeleteObject(blueBrush);


    RECT textRect = btnRect;
    textRect.top = textRect.bottom - 40;
    SetBkMode(dst, TRANSPARENT);

 //   mOldFont = (HFONT)SelectObject( mMemDC, mFont );
   int textLen = wcslen(wndText);
//    wndText = new wchar_t[textLen+2];
//    ZeroMemory(wndText, textLen+2 * sizeof(wchar_t));
//    GetWindowTextW(mHwnd, wndText, textLen+1);
    DrawTextEx( dst, wndText, textLen, &textRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_WORDBREAK, 0 );
//    SelectObject(mMemDC, mOldFont);
    delete(wndText);

}

void drawFooter(HDC dst, RECT footerRect)
{
    RECT topRect, botRect;
    topRect = botRect = footerRect;
    topRect.bottom = botRect.top = ((footerRect.bottom - footerRect.top)/2) + footerRect.top;

    GradientFillRect(dst, topRect, RGB(0x31,0x83,0x99), RGB(0x45,0xa7,0xc1), true);
    GradientFillRect(dst, botRect, RGB(0x45,0xa7,0xc1), RGB(0x31,0x83,0x99), true);
}

void drawHeader(HDC dst, RECT headerRect)
{
    HBRUSH b1;
    int i,j,headerHeight = (headerRect.bottom - headerRect.top)+1;

        b1 = CreateSolidBrush(RGB(230,230,230));
        FillRect(dst, &headerRect,b1);
        DeleteObject(b1);
        HPEN oldPen, curPen;
        curPen = CreatePen(PS_SOLID, 1, RGB(216,216,216));
        oldPen = (HPEN)SelectObject(dst, curPen);
        for (j=headerRect.top;j<headerRect.bottom;j+=10)
        {
            MoveToEx(dst, headerRect.left, j, NULL);
            LineTo(dst, headerRect.right, j);
        }

        for (i=headerRect.left;i<headerRect.right;i+=10)
        {
            MoveToEx(dst, i, headerRect.top, NULL);
            LineTo(dst, i, headerRect.bottom);
        }
        SelectObject(dst, oldPen);
        DeleteObject(curPen);
        MoveToEx(dst, headerRect.left,headerRect.bottom,NULL);
        LineTo(dst, headerRect.right,headerRect.bottom);
}

void onPaint(HWND hwndDlg, WPARAM wParam, LPARAM lParam)
{
    RECT mRect, topRect, midRect, botRect;
    RECT btnRects[4], orangeRect;
    PAINTSTRUCT ps;
    HDC hdc;
    const int bannerHeight = 120, footerHeight=32;
    int btnSize=150, margin=16;
    int i, j;

    // 1 calc rects for header, footer and body
    GetClientRect(hwndDlg, &mRect);
    topRect = midRect = botRect = mRect;
    topRect.bottom = topRect.top + bannerHeight;
    botRect.top = botRect.bottom - footerHeight;
    midRect.top = topRect.bottom;
    midRect.bottom = botRect.top;

    // 2. Reposition the 4 invisible big button controls (subclassed control with empty WM_PAINT and WM_ERASEBKG handlers)
    RECT tmpRect;
    HWND tmpWnd;
    int n = 4;
    for (i=0; i<n; i++)
    {
        tmpRect = bigBtns[i].rect;
        tmpWnd = GetDlgItem(hwndDlg, firstBigBtnId+i);
        SetWindowPos(tmpWnd,HWND_TOP,tmpRect.left,tmpRect.top,btnSize,btnSize,SWP_NOZORDER);
    }

    orangeRect.top = midRect.top + margin;
    orangeRect.bottom = midRect.bottom - margin;
    orangeRect.right = midRect.right - margin;
    orangeRect.left = orangeRect.right - (mRect.right-mRect.left)/4;

    HBRUSH b1,b2,b3;

    hdc = BeginPaint(hwndDlg, &ps);

        HBITMAP memBmp, oldMemBmp;
        HDC memDC;
        memDC = CreateCompatibleDC(hdc);
        memBmp = CreateCompatibleBitmap(hdc, mRect.right,mRect.bottom);
        oldMemBmp = (HBITMAP)SelectObject(memDC, memBmp);

        // center portion of backround
        diagGradFillRect(memDC, midRect, RGB(218,228,240), RGB(149,179,215), true);

//DeferWindowPos()

        // draw map
        Graphics *graphics;
        Image *mapImg;
        mapImg = Image::FromFile(L"map2.emf");
        graphics = Graphics::FromHDC(memDC);//(hdc);

        graphics->SetSmoothingMode( SmoothingModeHighQuality );
        graphics->SetInterpolationMode( InterpolationModeHighQualityBicubic );

        const int o_height = mapImg->GetHeight(), o_width =  mapImg->GetWidth();
        float scale = 0.5;
        int mapPosX, mapPosY;

        scale = (float)orangeRect.right / o_width;
        if ( (float)(orangeRect.bottom-orangeRect.left)/o_height  <  scale)
            scale = (float)(orangeRect.bottom-orangeRect.left)/o_height;

        int marginX = (orangeRect.right - orangeRect.left) - (o_width*scale);
        int marginY = (orangeRect.bottom - orangeRect.top) - (o_height*scale);

        marginX /= 2;
        marginY /= 2;

        mapPosX = orangeRect.left + marginX; //( ((orangeRect.right - orangeRect.left) - (o_width)) / 2);
        mapPosY = orangeRect.top + marginY; //( ((orangeRect.right - orangeRect.left) - (o_width)) / 2);

        squareRadialFillRect(memDC, orangeRect, RGB(0xff,0xc8,0xaa), RGB(0xff,0x96,0x48));
        graphics->DrawImage(mapImg,
                            mapPosX, //orangeRect.left + (((orangeRect.right-mRect.left)-(o_width/2) ) / 2),
                            mapPosY, //orangeRect.top,//orangeRect.top + (((orangeRect.bottom-mRect.top)-(o_height/2) ) / 2),
                            (int)(o_width*scale),(int)(o_height*scale) );
        delete graphics;
        delete mapImg;


        // header
        drawHeader(memDC, topRect);

        // draw footer
        drawFooter(memDC, botRect);

        // draw buttons
        for (i=0;i<4;i++)
            drawBigBtn(memDC, bigBtns[i].rect, bigBtns[i].text);

        BitBlt(hdc,0,0,mRect.right,mRect.bottom,memDC,0,0,SRCCOPY);
        SelectObject(memDC, oldMemBmp);
        DeleteObject(memBmp);
        DeleteDC(memDC);

    EndPaint(hwndDlg, &ps);
}

LRESULT CALLBACK invisibleBtnProc(HWND hwndBtn, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_PAINT:
        ValidateRect(hwndBtn, NULL);
        return 0;
    case WM_ERASEBKGND:
        return 1;
    }
    return CallWindowProc(oldBtnProc, hwndBtn, uMsg, wParam, lParam);
}


void onSize(HWND hwndDlg, WPARAM wParam, LPARAM lParam)
{
    RECT mRect, topRect, botRect, midRect;
    const int btnSize=150, margin=16;

    // 1 calc rects for header, footer and body
    GetClientRect(hwndDlg, &mRect);

    bigBtns[0].rect.left = ( 3  * ( mRect.right - mRect.left ) / 4 - 340 ) / 3;
    bigBtns[0].rect.top = 120 + mRect.top + ( mRect.bottom - mRect.top - 450 ) / 3;
    bigBtns[0].rect.right = bigBtns[0].rect.left + btnSize;
    bigBtns[0].rect.bottom = bigBtns[0].rect.top + btnSize;

    bigBtns[1].rect.left = 150 + 2 * ( 3  * ( mRect.right - mRect.left ) / 4 - 340 ) / 3;
    bigBtns[1].rect.top = 120 + ( mRect.bottom - mRect.top - 450 ) / 3;
    bigBtns[1].rect.right = bigBtns[1].rect.left + btnSize;
    bigBtns[1].rect.bottom = bigBtns[1].rect.top + btnSize;

    bigBtns[2].rect.left = ( 3  * ( mRect.right - mRect.left ) / 4 - 340 ) / 3;
    bigBtns[2].rect.top = 270 + 2 * ( mRect.bottom - mRect.top - 450 ) / 3;
    bigBtns[2].rect.right = bigBtns[2].rect.left + btnSize;
    bigBtns[2].rect.bottom = bigBtns[2].rect.top + btnSize;

    bigBtns[3].rect.left = 150 + 2 * ( 3  * ( mRect.right - mRect.left ) / 4 - 340 ) / 3;
    bigBtns[3].rect.top = 270 + 2 * ( mRect.bottom - mRect.top - 450 ) / 3;
    bigBtns[3].rect.right = bigBtns[3].rect.left + btnSize;
    bigBtns[3].rect.bottom = bigBtns[3].rect.top + btnSize;

    InvalidateRect(hwndDlg,NULL,false);
}

LRESULT CALLBACK DlgMain(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_INITDIALOG:
    {
        HWND btn;
        int i, n=4;
        SetWindowPos(hwndDlg, HWND_TOP, 200,150,996,547,SWP_NOZORDER);
        for (i=0; i<n; i++)
        {
            btn = CreateWindow(WC_BUTTON, L"", WS_VISIBLE|WS_CHILD, 0,0,0,0, hwndDlg, (HMENU)(firstBigBtnId+i), hInst, NULL);
            oldBtnProc = (WNDPROC)SetWindowLong(btn, GWL_WNDPROC, (long) invisibleBtnProc);
            printf("%ld\n", oldBtnProc);
        }
    }
    return TRUE;

    case WM_CLOSE:
    {
        EndDialog(hwndDlg, 0);
    }
    return TRUE;

    case WM_ERASEBKGND:
        return 1;

    case WM_PAINT:
            onPaint(hwndDlg, wParam, lParam);
        return 0;

    case WM_GETMINMAXINFO:
        MINMAXINFO *lpmmi;
        lpmmi = (LPMINMAXINFO) lParam;
        lpmmi->ptMinTrackSize.x = 996;
        lpmmi->ptMinTrackSize.y = 548;
        return 0;

    case WM_SIZE:
        onSize(hwndDlg, wParam, lParam);
        return 0;

    case WM_COMMAND:
    {
        switch(LOWORD(wParam))
        {
            case firstBigBtnId+0:
            case firstBigBtnId+1:
            case firstBigBtnId+2:
            case firstBigBtnId+3:
                MessageBeep(MB_ICONEXCLAMATION);
            break;
        }
    }
    return TRUE;
    }
    return FALSE;
}


int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR           gdiplusToken;
    hInst=hInstance;
    InitCommonControls();

	/************** Initialize GDI+. *************************/
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    int result = DialogBox(hInst, MAKEINTRESOURCE(DLG_MAIN), NULL, (DLGPROC)DlgMain);
  	GdiplusShutdown(gdiplusToken);
  	return result;
}


You should look at the WM_ERASEBKGND message. Basically return 0, this will indicate that the window still needs to be erased, and WM_PAINT should take responsibility for painting the control.



I believe that will solve your problem.
You should look at the WM_ERASEBKGND message. Basically return 0, this will indicate that the window still needs to be erased, and WM_PAINT should take responsibility for painting the control.

I believe that will solve your problem.


这篇关于没有经验的win32开发人员询问有关优化/改进WM_PAINT和WM_CTLCOLORSTATIC处理程序代码的建议/说明的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆