Hi,
......(I could not color code even one of the files as I exceeded 20,000 characters !)
I have a simple window with an Ownerdrawn button. This standalone .c source file compiles.
It does what it is supposed to, when the mouse passes over the window, the title text changes.
However I want to have this happen Only when I hover my button. As I understand it .... this means I must subclass the ownerdrawn button.
Here is the version that properly changes title text when you hover anywhere in the window:
(My text continues after the first file.)
#include <windows.h>
#include <stdio.h>
#define IDC_OWNERDRAWN1 1000
const char ClassName[] = "MainWindowClass";
const char ButtonClass[] = "BUTTON";
HWND hWndButton1;
HWND hWnd;
LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow )
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = ClassName;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Failed To Register The Window Class.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
HWND hWnd;
hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
ClassName,
"Just an OwnerDrawn needing Subclassing",
WS_OVERLAPPEDWINDOW,
200, 200, 375, 375,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
{
MessageBox(NULL, "Window Creation Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
static int cxClient, cyClient;
HDC hdc;
RECT rc;
PAINTSTRUCT ps;
HBRUSH NewBrush;
switch (Msg)
{
case WM_CREATE:
{
hWndButton1 = CreateWindowEx(
0,
ButtonClass,
NULL,
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
CW_USEDEFAULT, CW_USEDEFAULT,
250, 30,
hWnd,
(HMENU)IDC_OWNERDRAWN1,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL);\
if(!hWndButton1)
{
MessageBox(NULL, "Button Creation Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;\
}\
ShowWindow(hWndButton1, SW_SHOW);
UpdateWindow(hWndButton1);
return 0 ;
}
break;
case WM_DRAWITEM:
{
switch ((UINT)wParam)
{
case IDC_OWNERDRAWN1:
{
LPDRAWITEMSTRUCT lpdis = (DRAWITEMSTRUCT*)lParam;
SIZE size;
char text[256];
sprintf(text, "%s", "Button");
GetTextExtentPoint32(lpdis->hDC, text, strlen(text), &size);
ExtTextOut(lpdis->hDC,
((lpdis->rcItem.right - lpdis->rcItem.left) - size.cx) / 2,
((lpdis->rcItem.bottom - lpdis->rcItem.top) - size.cy) / 2,
ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem, text, strlen(text), NULL);
DrawEdge(lpdis->hDC, &lpdis->rcItem,
(lpdis->itemState & ODS_SELECTED ?
EDGE_SUNKEN : EDGE_RAISED ), BF_RECT);
return TRUE;
}
break;
}
}
break;
case WM_PAINT :
{
hdc = BeginPaint (hWnd, &ps) ;
NewBrush = CreateSolidBrush(RGB(250, 25, 5));
SelectObject(hdc, NewBrush);
Rectangle(hdc,
0,
0,
375,
375);
GetClientRect(hWnd, &rc);
SetTextColor(hdc, RGB(240,240,96));
SetBkMode(hdc, TRANSPARENT);
EndPaint (hWnd, &ps) ;
DeleteObject(NewBrush);
return 0 ;
}
case WM_SIZE :
{
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
// Move the button to the center.
MoveWindow (hWndButton1,
cxClient / 2 - 250 /2,
(cyClient / 2 - 30 / 2),
250,
30,
TRUE);
return 0 ;
}
break;
// // ~ • • • • • • • • • • • •
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER;
tme.dwHoverTime = 100;
tme.hwndTrack = hWnd;
TrackMouseEvent(&tme);
return 0 ;
}
break;
case WM_MOUSEHOVER:
{
SetWindowText(hWnd, "WM_MOUSEHOVER!");
return 0 ;
}
break;
// // ~ • • • • • • • • • • • •
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, Msg, wParam, lParam));
}
return 0;
}
After much research and struggle I converted the first file to the following attempting to subclass the button.
To modify the above, I moved the mouse switch case statements out of the mainwindow to my subclassed button procedure,
Here is my attempt.
#include <windows.h>
#include <stdio.h>
#include <winuser.h>
#define IDC_OWNERDRAWN1 1000
const char ClassName[] = "MainWindowClass";
const char ButtonClass[] = "BUTTON";
HWND hWndButton1;
HWND hWnd;
// // ~ • • • • • • • • • • • •
WNDPROC wpOrigProc;
LRESULT APIENTRY Btn1Proc(HWND hWndButton1, UINT uMsg, WPARAM wParam, LPARAM lParam);
// // ~ • • • • • • • • • • • •
LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam );
MSG Msg, uMsg;
INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow )
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = 0;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = ClassName;
if (!RegisterClassEx(&wc))
{
MessageBox(NULL, "Failed To Register The Window Class.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
HWND hWnd;
hWnd = CreateWindowEx(
WS_EX_CLIENTEDGE,
ClassName,
"Just an OwnerDrawn needing Subclassing",
WS_OVERLAPPEDWINDOW,
200, 200, 375, 375,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd)
{
MessageBox(NULL, "Window Creation Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow(hWnd, SW_SHOW);
UpdateWindow(hWnd);
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
return Msg.wParam;
}
LRESULT CALLBACK WndProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam )
{
static int cxClient, cyClient;
HDC hdc;
RECT rc;
PAINTSTRUCT ps;
HBRUSH NewBrush;
switch (Msg)
{
case WM_CREATE:
{
hWndButton1 = CreateWindowEx(
0,
ButtonClass,
NULL,
WS_CHILD | WS_VISIBLE | BS_OWNERDRAW,
CW_USEDEFAULT, CW_USEDEFAULT,
250, 30,
hWnd,
(HMENU)IDC_OWNERDRAWN1,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE),
NULL);
if(!hWndButton1)
{
MessageBox(NULL, "Button Creation Failed.", "Error", MB_OK | MB_ICONERROR);
return 0;
}
ShowWindow(hWndButton1, SW_SHOW);
UpdateWindow(hWndButton1);
// // ~ • • • • • • • • • • • •
// Subclass the buttton.
wpOrigProc = (WNDPROC)SetWindowLong(GetDlgItem(hWndButton1, IDC_OWNERDRAWN1), GWL_WNDPROC, (LONG)Btn1Proc);
// // ~ • • • • • • • • • • • •
return TRUE ;
}
break;
case WM_DRAWITEM:
{
switch ((UINT)wParam)
{
case IDC_OWNERDRAWN1:
{
LPDRAWITEMSTRUCT lpdis = (DRAWITEMSTRUCT*)lParam;
SIZE size;
char text[256];
sprintf(text, "%s", "Button");
GetTextExtentPoint32(lpdis->hDC, text, strlen(text), &size);
ExtTextOut(lpdis->hDC,
((lpdis->rcItem.right - lpdis->rcItem.left) - size.cx) / 2,
((lpdis->rcItem.bottom - lpdis->rcItem.top) - size.cy) / 2,
ETO_OPAQUE | ETO_CLIPPED, &lpdis->rcItem, text, strlen(text), NULL);
DrawEdge(lpdis->hDC, &lpdis->rcItem,
(lpdis->itemState & ODS_SELECTED ?
EDGE_SUNKEN : EDGE_RAISED ), BF_RECT);
return TRUE;
}
break;
}
}
break;
case WM_PAINT :
{
hdc = BeginPaint (hWnd, &ps) ;
NewBrush = CreateSolidBrush(RGB(250, 25, 5));
SelectObject(hdc, NewBrush);
Rectangle(hdc,
0,
0,
375,
375);
GetClientRect(hWnd, &rc);
SetTextColor(hdc, RGB(240,240,96));
SetBkMode(hdc, TRANSPARENT);
EndPaint (hWnd, &ps) ;
DeleteObject(NewBrush);
return 0 ;
}
case WM_SIZE :
{
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
// Move the button to the center.
MoveWindow (hWndButton1,
cxClient / 2 - 250 /2,
(cyClient / 2 - 30 / 2),
250,
30,
TRUE);
return 0 ;
}
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
SetWindowLong(hWndButton1, GWL_WNDPROC, (LONG) wpOrigProc);
break;
default:
return (DefWindowProc(hWnd, Msg, wParam, lParam));
}
return 0;
}
// // ~ • • • • • • • • • • • •
LRESULT APIENTRY Btn1Proc(HWND hWndButton1, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_MOUSEMOVE:
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_HOVER;
tme.dwHoverTime = 100;
tme.hwndTrack = hWndButton1; //......................orig hWnd
TrackMouseEvent(&tme);
return TRUE;
}
break;
case WM_MOUSEHOVER:
{
MessageBox(hWnd, "Text in Window", "Well", MB_OK | MB_ICONINFORMATION);
SetWindowText(hWnd, "WM_MOUSEHOVER!");
return TRUE ;
}
break;
default:
return CallWindowProc(wpOrigProc, hWndButton1, uMsg, wParam, lParam);
}
// // ~ • • • • • • • • • • • •
}
"// // ~ • • • • • • • • • • " Marks code block changes I made.
The above builds with out errors or warnings.
I need help, as I am not getting any further !
Much of the code I can find on the internet is for subclassing an edit control, or is using C++ or Vb,
NEVER do I see code that is very close to what I am trying to do (on the subject of subclassing).
I know I am not subclassing or ..... having the right returns or something.
My understanding of the win32 api is at the ragged edge here........ !!
Petzold does not even mention the function " WM_MOUSEHOVER" in his book and neither to others.
It is a tough life !!!!
If I can properly subclass my button, I will change the window title when I hover the button !
Then I can start to play with functions like WM_MOUSELEAVE etc. !!!!!
Thanks in advance.
Ed