Windows API:为什么按钮悬停效果会在一段时间后卡住?

时间:2016-03-04 11:58:36

标签: c++ windows button

最近开始使用Windows API开发,我决定了一些交互性。所以计划是使用所有者绘制的按钮,当鼠标进入矩形区域时会改变背景颜色,当鼠标离开时会改变回原来的颜色。

我制作了3个这样的按钮,并用自己的自定义窗口程序对它们进行了分类。现在因为实际上没有WM_MOUSEENTER消息,我使用WM_MOUSEMOVE和一些鼠标跟踪来填充具有特定颜色的窗口。这基本上意味着每次光标在窗口内移动时矩形都会被填充。

当鼠标指针移动到按钮的矩形之外时,我还使用WM_MOUSELEAVE来填充按钮。

这似乎最初工作正常,但过了一会儿,矩形填充将停止,背景将卡在悬停颜色或默认颜色。

这是代码

#ifndef UWMENU_H_INCLUDED
#define UWMENU_H_INCLUDED
#endif // UWMENU_H_INCLUDED

#include <iostream>
using namespace std;

LRESULT CALLBACK DBWndProc(HWND, UINT, WPARAM, LPARAM);
WNDPROC DBWndProcOld[3];

class UWMenu{
    public:
    //WINDOW PROCEDURE FOR NEWS BUTTON
    static LRESULT CALLBACK DBWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){
        HBRUSH BG_btnOne = CreateSolidBrush(NAV_BTN_DEF_CLR);
        HBRUSH BG_btnOneOver = CreateSolidBrush(NAV_BTN_OVER_CLR);

        int btnID = GetDlgCtrlID(hwnd);
        cout << btnID << "\n";

        switch(msg){
            case WM_MOUSEMOVE:{

                cout << "Mouse is hovering over button\n";
                SetCursor(LoadCursor(NULL, IDC_HAND));
                HDC hdc = GetDC(hwnd);
                RECT rc;
                rc.left = 0;                            //Top left X coordinate of button's rectangular area
                rc.top = 0;                             //Top left Y coordinate of button's rectangular area
                rc.right = NAV_BTN_WIDTH;               //Bottom right X coordinate of button's rectangular area
                rc.bottom = NAV_BTN_HEIGHT;             //Bottom right Y coordinate of button's rectangular area

                printf("Repainting button background color\n");
                FillRect(hdc, &rc, BG_btnOneOver);
                SetTextColor(hdc, RGB(255,255,255));
                SetBkMode(hdc, TRANSPARENT);

                if(btnID == NBID_NEWS){DrawText(hdc, TXT_BN_NEWS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                if(btnID == NBID_TOOLS){DrawText(hdc, TXT_BN_TOOLS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                if(btnID == NBID_EDITOR){DrawText(hdc, TXT_BN_EDITORS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                ReleaseDC(hwnd, hdc);

                TRACKMOUSEEVENT tme;
                tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = hwnd;
                tme.dwHoverTime = HOVER_DEFAULT;
                TrackMouseEvent(&tme);
            }
            break;

            case WM_MOUSELEAVE:{
                printf("You left me\n");
                SetCursor(LoadCursor(NULL, IDC_ARROW));

                HDC hdc = GetDC(hwnd);
                RECT rc;
                rc.left = 0;                                //Top left X coordinate of button's rectangular area
                rc.top = 0;                                 //Top left Y coordinate of button's rectangular area
                rc.right = NAV_BTN_WIDTH;                   //Bottom right X coordinate of button's rectangular area
                rc.bottom = NAV_BTN_HEIGHT;                 //Bottom right Y coordinate of button's rectangular area

                FillRect(hdc, &rc, BG_btnOne);
                SetTextColor(hdc, RGB(255,255,255));
                SetBkMode(hdc, TRANSPARENT);
                if(btnID == NBID_NEWS){DrawText(hdc, TXT_BN_NEWS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                if(btnID == NBID_TOOLS){DrawText(hdc, TXT_BN_TOOLS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                if(btnID == NBID_EDITOR){DrawText(hdc, TXT_BN_EDITORS, -1, &rc, DT_SINGLELINE | DT_CENTER | DT_VCENTER);}
                ReleaseDC(hwnd, hdc);

                TRACKMOUSEEVENT tme;
                tme.cbSize = sizeof(TRACKMOUSEEVENT);
                tme.dwFlags = TME_CANCEL;
                tme.hwndTrack = hwnd;
                tme.dwHoverTime = HOVER_DEFAULT;
                TrackMouseEvent(&tme);
            }
            break;
        }
        return CallWindowProc(DBWndProcOld[btnID-200], hwnd, msg, wParam, lParam);
    }
};

正在处理mouse_move消息,因为当鼠标移过按钮时,printf()cout的输出会以调试模式显示。

有什么方法可以解决这个问题吗?可能与鼠标跟踪有关吗?

我认为问题在于,当指针位于矩形内部时,按钮会被FillRect()发送垃圾邮件。

感谢任何帮助。

1 个答案:

答案 0 :(得分:2)

此问题现已解决。这是由于GDI泄漏。通过删除在父窗口过程中重复创建的画笔来解决该问题。