Sign in to follow this  

win32 Custom control problem

This topic is 3862 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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

This topic is 3862 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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