Sign in to follow this  
Gavinl

win32 Custom control problem

Recommended Posts

Hello everyone, I'm sorry I didn't know where to post my problem. I hope this is the right forum. Anyways, I'm trying to learn how to create a custom control using win32 and GDI. I decided to try to create an XP style button from scratch. So far its working very nicely, I got it drawn the way I want. Now the problem is redrawing it when the mouse is over the button. I have it set so that the message checks when the mouse is moved over the control and sets a boolean value to true. Then sends a WM_PAINT message to the control to redraw it. The problem is that it does redraw the control, but it doesn't get updated on the screen. If I put the cursor over the button, the boolean value gets set and the paint message gets sent, but it will only redraw the button if i move the window so that the button is off the screen, then move it back into view. Here's a link to the compiled .exe and the source code is below. Custon Button the DrawBackgroundPattern function is what does all the drawing. And the buttonProc function handles all the messages. I guess thats where the problem might arise. But I'm not too sure
/**************************
 * Includes
 *
 **************************/

#include <stdio.h>

#include <windows.h>
#include <string>

using namespace std;

// Handle to the edit box control
HWND hWnd3;

string output;

/**************************
 * Function Declarations
 *
 **************************/

LRESULT CALLBACK WndProc (HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK buttonProc (HWND hWnd, UINT message,WPARAM wParam, LPARAM lParam);

// Structure for my custom button control
typedef struct {
        bool state; // true means its high-lighted, false means its not.
} xpButtonStruct;




void DrawBackgroundPattern(HWND hWnd)

{

    PAINTSTRUCT ps;
    HDC hDC = BeginPaint(hWnd, &ps);  
            
   RECT rectFill;          // Rectangle for filling band
   RECT rectClient;        // Rectangle for entire client area
   float fStep;            // How large is each band?
   HBRUSH hBrush;



    // vars
    HDC bufDC;
    HBITMAP bufBMP;

    GetWindowRect(hWnd, &rectClient);
    // set up
    bufDC = CreateCompatibleDC(hDC);
    bufBMP = CreateCompatibleBitmap(hDC, rectClient.right, rectClient.bottom);
    SelectObject(bufDC, bufBMP);
    
    GetClientRect(hWnd, &rectClient);


   // How large is the area you need to fill?

   GetClientRect(hWnd, &rectClient);

   // Determine how large each band should be in order to cover the
   // client with 256 bands (one for every color intensity level)

   fStep = (float)rectClient.bottom / 50.0f;

   SetBkMode(hDC, TRANSPARENT); 
   SetBkMode(bufDC, TRANSPARENT); 

   
   for(int i=0;i<rectClient.bottom;i++){

            SetRect(&rectFill,
                    0,                           // Upper left X
                    (int)(i),      // Upper left Y
                    rectClient.right,          // Lower right X
                    (int)((i+1))); // Lower right Y           

           int c = (255 - (int)(50*(float)i/(float)(rectClient.bottom)) );
           hBrush = CreateSolidBrush(RGB(c, c, c ));

           // Fill the rectangle
           FillRect(bufDC, &rectFill, hBrush);
        
           // Get rid of the brush you created
           DeleteObject(hBrush);                    
   };
   
   hBrush = (HBRUSH) COLOR_BACKGROUND;
      
   SetRect(&rectFill,0,0,2,2);
   FillRect(bufDC, &rectFill, hBrush);   
   
   SetRect(&rectFill,rectClient.right-3,0,rectClient.right,1);
   FillRect(bufDC, &rectFill, hBrush);  

   SetRect(&rectFill,rectClient.right-3,rectClient.bottom-3,rectClient.right,rectClient.bottom);
   FillRect(bufDC, &rectFill, hBrush);            

   SetRect(&rectFill,0,rectClient.bottom-3,3,rectClient.bottom);
   FillRect(bufDC, &rectFill, hBrush);     




    //GetWindowRect(hWnd, &rectClient);
   
    POINT p;
    MoveToEx(bufDC, 2, 0,&p);

    LineTo(bufDC, rectClient.right-3, 0);
    LineTo(bufDC, rectClient.right-1, 2);

    LineTo(bufDC, rectClient.right-1, rectClient.bottom-3);
    LineTo(bufDC, rectClient.right-2, rectClient.bottom-1);

    LineTo(bufDC, 2, rectClient.bottom-1);
    LineTo(bufDC, 0, rectClient.bottom-3);

    LineTo(bufDC, 0, 2);
    LineTo(bufDC, 2, 0);

    int l = GetWindowTextLength(hWnd)+2;       
    char c[l];
    GetWindowText( hWnd, c, l );
    DrawText(bufDC,   c,   -1,   &rectClient,   DT_CENTER|DT_SINGLELINE|DT_VCENTER);
   
   
   
   xpButtonStruct * g = (xpButtonStruct*)GetWindowLong(hWnd, GWL_USERDATA);
   
   if(g->state){
        HPEN hPen = CreatePen(   PS_SOLID,   1, 0x0000FFFF );
        HPEN hPenOld = (HPEN)SelectObject(bufDC, hPen);   
        
        MoveToEx(bufDC, 2, 2,&p);   
        LineTo(bufDC, rectClient.right-3, 2);
        LineTo(bufDC, rectClient.right-3, rectClient.bottom-3);      
        LineTo(bufDC, 2, rectClient.bottom-3);      
        LineTo(bufDC, 2, 2);    

        SetWindowText(hWnd3, output.c_str());  
        
        SelectObject(bufDC, hPenOld);                
   }   


   GetWindowRect(hWnd, &rectClient);   
   
   BitBlt(hDC, 0, 0, rectClient.right, rectClient.bottom, bufDC, 0, 0, SRCCOPY);
   // Give back the DC

   ReleaseDC(hWnd, bufDC);
   DeleteDC(bufDC);

   EndPaint(hWnd, &ps);
  output += "Re painted the button\r\n"; 
 

}




/**************************
 * WinMain
 *
 **************************/


int WINAPI WinMain (HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpCmdLine,
                    int iCmdShow)
{

    WNDCLASS wc, buttonClass;
    
    HWND hWnd,       // handle to my window
         hWnd2;      // handle to my custon button

    MSG msg;
    BOOL bQuit = FALSE;


    /* register window class */
    wc.style = CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor (NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;    
    wc.lpszMenuName = NULL;
    wc.lpszClassName = "mywin";
    RegisterClass (&wc);

    /* create main window */
    hWnd = CreateWindow (
      "mywin", "User Created Control test", 
      WS_CAPTION | WS_POPUPWINDOW | WS_VISIBLE,
      0, 0, 640, 480,
      NULL, NULL, hInstance, NULL);
      





    /* register my custom button class */
    buttonClass.style = CS_OWNDC|CS_HREDRAW|CS_VREDRAW;
    buttonClass.lpfnWndProc = buttonProc;
    buttonClass.cbClsExtra = 0;
    buttonClass.cbWndExtra = 0;
    buttonClass.hInstance = hInstance;
    buttonClass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    buttonClass.hCursor = LoadCursor (NULL, IDC_ARROW);
    buttonClass.hbrBackground = (HBRUSH) COLOR_BACKGROUND;    
    buttonClass.lpszMenuName = NULL;
    buttonClass.lpszClassName = "xpButton";
    RegisterClass (&buttonClass);

    /* create main window */
    hWnd2 = CreateWindow (
      "xpButton", "Test Button", 
      WS_CHILD | WS_VISIBLE ,
      20, 20, 200, 50,
      hWnd, NULL, hInstance, NULL);









    hWnd3 = CreateWindow (
      "EDIT", "", 
      WS_CHILD | WS_VISIBLE | ES_AUTOVSCROLL | ES_MULTILINE | WS_VSCROLL,
      100, 100, 400, 300,
      hWnd, NULL, hInstance, NULL);

    /* program main loop */
    while (!bQuit)
    {
        /* check for messages */
        if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
        {
            /* handle or dispatch messages */
            if (msg.message == WM_QUIT)
            {
                bQuit = TRUE;
            }
            else
            {
                TranslateMessage (&msg);
                DispatchMessage (&msg);
            }
        }
        Sleep(1);
    }

    DestroyWindow (hWnd);

    return msg.wParam;
}


/* Procedure for my custom button */
LRESULT CALLBACK buttonProc (HWND hWnd, UINT message,
                          WPARAM wParam, LPARAM lParam)
{


    switch (message)
    {
    case WM_CREATE:{
            xpButtonStruct * p = new xpButtonStruct;
            p->state = false;
            SetWindowLong(hWnd, GWL_USERDATA, (LONG)p );  

            return 0;
        }
    case WM_CLOSE:
        PostQuitMessage (0);
        return 0;
        
        
    case WM_MOUSEMOVE: {
             HWND parent = GetParent(hWnd);
             xpButtonStruct * p = (xpButtonStruct*)GetWindowLong(hWnd, GWL_USERDATA);
             p->state = true;
             output += "Mouse Move\r\n";
             SetWindowText(hWnd3, output.c_str());
             SendMessage(hWnd, WM_PAINT, 0, 0);
         }
         return(0);
    case WM_MOUSELEAVE:{
         // This doesn't seem to work
             xpButtonStruct * p = (xpButtonStruct*)GetWindowLong(hWnd, GWL_USERDATA);
             p->state = false;
             output += "Mouse exit\r\n";
             SetWindowText(hWnd3, output.c_str()); 
             UpdateWindow(hWnd);
         }
         break;
    case WM_DESTROY:{
        xpButtonStruct * p = (xpButtonStruct*)GetWindowLong(hWnd, GWL_USERDATA);
        delete (p);
        return 0;}
    case WM_PAINT:{

             DrawBackgroundPattern(hWnd); 
        
             return 0; 
        }
    default:  
        return DefWindowProc (hWnd, message, wParam, lParam);
        
        
    }

}
/********************
 * Window Procedure
 *
 ********************/

LRESULT CALLBACK WndProc (HWND hWnd, UINT message,
                          WPARAM wParam, LPARAM lParam)
{

    switch (message)
    {
    case WM_CREATE:
        return 0;
    case WM_CLOSE:
        PostQuitMessage (0);
        return 0;

    case WM_DESTROY:
        return 0;
    case WM_KEYUP:
         break;
    case WM_KEYDOWN:
        switch (wParam)
        {   
        case VK_ESCAPE:
            PostQuitMessage(0);
            return 0;
        }
        return 0;

    default:
        return DefWindowProc (hWnd, message, wParam, lParam);
    }
}



Share this post


Link to post
Share on other sites
Hello the code looks quite nice.

i noticed you use UpdateWindow im not sure about this but you might get what your looking for by using

bool InvalidateRect(HWND hWnd,const RECT* lpRect, BOOL bErase);

i cant remmber the exact reason as to why the window will not update but i belive
if you try that function it should work if not ill look up so older code somewhere on my computer.

im sure i got an example somewhere that will answer your question but i am fairly
sure invalidate rect will help!

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this