2

我将 c++ 与 win32 和 gdi+ 一起用于图形。
当我在 WM_CREATE 之外初始化一个按钮时,特别是在 WM_TIMER 消息中,在绘制一帧之后,我无法绘制任何其他内容。这是代码片段:

case WM_TIMER:
    RECT client;
    GetClientRect(hWnd, &client);
    client.bottom-=100; //The bottom hundred pixels are static after I draw the first frame, so I never update them
    if(starting==true)
    {
        starting=false;
        hdc = GetDC(hWnd);
        hdcBuf = CreateCompatibleDC(hdc);
        hdcMem = CreateCompatibleDC(hdcBuf);
        hbmBackBM = CreateCompatibleBitmap(hdc, client.right, client.bottom );
        hbmOldBackBM = (HBITMAP)SelectObject(hdcBuf, hbmBackBM);

        Graphics temp(hdc);
        SolidBrush yelloworange(Color(250,225,65));
        temp.FillRectangle(&yelloworange,0,client.bottom,client.right,100); //Fill the bottom with yellow
        buttons[0]=CreateWindow("button","makereg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 630, 60, 20, hWnd, HMENU(IDB_MAKEREG), NULL, NULL);
        //buttons[1]=CreateWindow("button","destroyreg", WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 100, 670, 80, 20, hWnd, HMENU(IDB_MAKEREG+1), NULL, NULL);
    }
    Graphics g(hdcBuf);

第一部分用于双缓冲,我实例化的变量是全局的。我删除了 WM_DESTROY 中的 HDC 和 HBITMAP。开始是一个全局布尔值,被实例化为真。我在这条 WM_TIMER 消息中完成了我所有的绘图。如果我只注释掉创建按钮的两行,一切都会正常运行。有了它们,它只画出这个 WM_TIMER 中剩下的东西,而不画下一个。所有其他绘图代码都对 hdcBuf 或 g 完成,然后 hdcBuf 被 BitBlt'd 到 hdc 上。

我尝试在 WM_CREATE 中创建按钮,然后在 WM_TIMER 中显示它,但这导致了同样的问题。我无法在 WM_CREATE 中创建和显示窗口,否则当我用黄色填充底部 100 个像素时,它会被覆盖。

有没有办法在 WM_CREATE 和 WM_PAINT 之外创建和显示一个按钮而不会使其余代码崩溃?

编辑:这是一些在 WM_TIMER 中停止工作的代码:

if(mousex!=uptomousex && mousey!=uptomousey && lbuttondown==true) // this code draws a rectangle between the point where the user begins holding the left mousebutton, and where the mouse is right now.
{
    if(uptomousex-mousex>0 && uptomousey-mousey>0)
        g.DrawRectangle(&(p[0]), mousex, mousey, uptomousex-mousex, uptomousey-mousey);
    else if(uptomousex-mousex<0 && uptomousey-mousey>0)
        g.DrawRectangle((&p[0]), uptomousex, mousey, mousex-uptomousex, uptomousey-mousey);
    else if(uptomousex-mousex>0 && uptomousey-mousey<0)
        g.DrawRectangle((&p[0]), mousex, uptomousey, uptomousex-mousex, mousey-uptomousey);
    else if(uptomousex-mousex<0 && uptomousey-mousey<0)
        g.DrawRectangle(&(p[0]), uptomousex, uptomousey, mousex-uptomousex, mousey-uptomousey);
}

一些全局变量:

bool lbuttondown=false;
float mousex=0;
float mousey=0;
float uptomousex=0;
float uptomousey=0;

在 WndProc 的其他地方...

case WM_LBUTTONDOWN:
    lbuttondown=true;
    mousex=(float)GET_X_LPARAM(lParam);
    mousey=(float)GET_Y_LPARAM(lParam);
    uptomousex=mousex;
    uptomousey=mousey;
    break;
case WM_MOUSEMOVE:
    if(mousex!=GET_X_LPARAM(lParam) && mousey!=GET_Y_LPARAM(lParam))
    {
        uptomousex=(float)GET_X_LPARAM(lParam);
        uptomousey=(float)GET_Y_LPARAM(lParam);
    }
    break;
4

2 回答 2

1

您在每个计时器调用上创建/获取至少 3 个设备上下文实例,并且您永远不会删除/释放它们(至少在您发布的示例中),因此您以粉碎整个 GDI 系统而告终也就不足为奇了。

对于每个 GetDC() 调用,应该调用 ReleaseDC(),

对于每个 CreateCompatibleDC() 调用,都应该调用 DeleteObject()。

于 2012-12-24T15:42:50.990 回答
0

我还没有弄清楚为什么会发生这种情况,但我创建了一个简单的补丁:我自己的按钮类,我将在这里分享:

class button
{
public:
    int x;
    int y;
    int width;
    int height;
    string text;
    void (*func)(short);
    button(int px, int py, int w, int h, string txt, void (*f)(short))
    {
        x=px;
        y=py;
        width=w;
        height=h;
        text=txt;
        func=*f;
    }
};

然后,有一个全局的按钮向量,allbuttons,在 WM_LBUTTONUP 消息中,我循环遍历所有按钮并检查单击是否在按钮中,如果是,我调用 func。

它简单,更灵活,并且确实有效。但是,图形更糟,出于好奇,我仍然想找出Windows按钮功能失调的原因。

于 2012-12-24T15:22:01.140 回答