Reputation: 139
Having recently started developing with the Windows API, I decided some interactivity was in order. So the plan was to use Owner Drawn buttons that would change background colour when the mouse enters their rectangular area, and changes back to the original colour when the mouse leaves.
I made 3 such buttons and sub-classed them with their own custom window procedure. Now because there is really no such thing as a WM_MOUSEENTER
message I used the WM_MOUSEMOVE
and some mouse tracking to Fill the window with a certain colour. This basically means the rectangle gets filled every time the cursor moves inside the window.
I also used WM_MOUSELEAVE
to fill the button when the mouse pointer moves outside the button's rectangle.
And this seems to work fine at first but after a while the rectangle filling will stop and the background will be stuck in either the hover colour or the default colour.
Here's the Code
#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);
}
};
The mouse_move messages are being processed as the output from printf()
and cout
are shown in debug mode when the mouse moves over the buttons.
Is there any way to fix this? Something to do with mouse tracking perhaps?
I think the problem is that the button is sort of getting spammed with the FillRect()
while the pointer is inside its rectangle.
Any help is appreciated.
Upvotes: 2
Views: 121
Reputation: 139
This problem has been solved now. It was due to a GDI leak. The problem was solved by deleting brushes that were being created repeatedly in a parent window procedure.
Upvotes: 2