NO

Author Topic: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!  (Read 4960 times)

EdPellesC99

  • Guest
   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.)


Code: [Select]
#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.

Code: [Select]

#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




« Last Edit: December 23, 2010, 02:54:53 AM by EdPellesC99 »

EdPellesC99

  • Guest
Re: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!
« Reply #1 on: December 23, 2010, 03:00:15 AM »

   I just modified my second file slightly changing "myBtnProc" to "wpOrigProc" (as my names were confusing) and adding a line to the WM_DESTROY case.

...Ed


Offline DMac

  • Member
  • *
  • Posts: 272
Re: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!
« Reply #2 on: December 23, 2010, 04:45:39 AM »
Here's an example that I just threw together.

Perhaps this might give you some ideas.

Regards,
DMac.
No one cares how much you know,
until they know how much you care.

EdPellesC99

  • Guest
Re: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!
« Reply #3 on: December 23, 2010, 06:00:09 AM »


    Thanks Sooo much for the reply DMac, I will be checking it out !!!!

.........Ed

EdPellesC99

  • Guest
Re: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!
« Reply #4 on: December 23, 2010, 06:42:18 AM »

    DMac,

    It is terrific work. Yes I will be able to learn a lot from this ! (in time !)

My problem is I was trying to start out (for my brain to grasp things) a little more simply :).

This seems pretty advanced !


  I have been wondering if what I want to do (tweak my code the minimum and get it to work) is impossible.

I have seen complicated examples written in C++ usually the code used the commctrl.h file, and a dialog.

Then I had the impossible task of converting it to C.


   Trust me I will be breaking this down and trying to grasp it tommorrow +.....

I would prefer to study this as "Subclassing a Button Phase II for Ed" though  .............     :)  :)

   Thank you very much. You gave me the best code I have seen yet, that also does what I want !  ......AND is in C,  AND compiles with PellesC ! And looks and behaves just like what I wanted.

   And if the day comes that I can throw something like that together, I will buy you a beer !

In the meantime though you are on your own ! and don't get your hopes up for a free beer soon :)

   If I could find out that what I wanted to do was not possible, then that would be good to know.... and I could move forward.

   Maybe I can figure out what was going wrong with mine by studying yours. The critical thing is I can compile and test now.

   Thanks much, now I'll get out my magnifying glass and start looking over that code !!!

......Ed   



EdPellesC99

  • Guest
Re: Subclass an OwnerDrawn Button.Close but no Cigar .......... Help !!!!
« Reply #5 on: December 31, 2010, 12:03:08 AM »
4-56 pm  12-30-10

   Dmac,

   Just want you to know I am still working on this. I have never seen yet subclassing a button that did not have the button in a dialog.

You have the only hovering eg. ....I have ever seen on a subclassed button in C.

   Often times people hover a button and change the cursor, but that can be done on a button that is not subclassed.

Your changing window properties are the key, I realize this ...... It may take me a week or two yet! (if I am lucky)

   Just want you to know! Happy New Years to you and all forum buddies !!!!!!

   ........ Ed