Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C++ (http://www.go4expert.com/articles/cpp-tutorials/)
-   -   Custom Image Button (http://www.go4expert.com/articles/custom-image-button-t7580/)

shabbir 27Nov2007 21:13

Custom Image Button
 
2 Attachment(s)

Steps to integrate code into your programs



This is an easy and flexible way to use bitmaps as buttons in your application, and here are the detail steps of how you can add the custom button to your application.
  1. Create a new MFC AppWizard (exe) based project and name it as BtnSample

    http://www.go4expert.com/images/arti...tton/step1.png

  2. Select dialog based and click on Finish

    http://www.go4expert.com/images/arti...tton/step2.png

  3. You will see the following dialog and click on OK button

    http://www.go4expert.com/images/arti...tton/step3.png

  4. After some progress bars you will see the following project created for you.

    http://www.go4expert.com/images/arti...tton/step4.png

  5. Now Add a button to the Dialog Application from the Control Toolbox

    http://www.go4expert.com/images/arti...tton/step5.png

  6. Now Copy the GuiButton.h and GuiButton.cpp files from the attachment into your project location and Add the files to the workspace.

    http://www.go4expert.com/images/arti...tton/step6.png

  7. Add a variable to the button using the class wizard and keep the variable type as CButton

    http://www.go4expert.com/images/arti...tton/step7.png

  8. Open BtnSampleDlg.h and change the variable type you have created in the above step from CButton to CGuiButton and add the
    Code: Cpp

    #include "GuiButton.h"

    at the top of the file.
  9. Now copy the bitmap you would like to use for your button and add import the bitmap resource into the project

    http://www.go4expert.com/images/arti...tton/step8.png

  10. Finally add the following line in the OnInitDialog of your dialog in the file BtnSampleDlg.cpp. Remember to skip the About Dialog classes.
    Code: Cpp

    m_btn.SetSkin(IDB_BITMAP1);

  11. If you have successfully done all the steps try compiling and runing the program and you should see

    http://www.go4expert.com/images/arti...tton/step9.png

What is it in the code ...



This was all about running the program and integrating the GuiButton into your project but what is there in the GuiButton I will try to explain that as well.
First the SetSkin function.
Code: Cpp

/////////////////////////////////////////////////////////////////////////
/// <b>Function: SetSkin</b>
///
/// \param  uiNormal  (in) Normal Bitmap ID
///
/// \param  uiDisabled    (in) Disabled Bitmap ID
///
/// \param  clrTextColor  (in) Text Color where default color is white
///
/// \return void
///
/// \remarks    Sets the skin to the button
///
/////////////////////////////////////////////////////////////////////////
void CGuiButton::SetSkin(UINT uiNormal, UINT uiDisabled, COLORREF clrTextColor)
{
    TRACE(TEXT("CGuiButton::SetSkin\n"));
    // --------------------------------------
    // Free previous allocated bitmaps
    // --------------------------------------
    m_NormalBitmapDC.DeleteObject();
    m_DisabledBitmapDC.DeleteObject();

    // --------------------------------------
    // Load bitmaps corresponding to states
    // --------------------------------------
    if (uiNormal>0)
        m_NormalBitmapDC.LoadBitmap(uiNormal);
    if (uiDisabled>0)
        m_DisabledBitmapDC.LoadBitmap(uiDisabled);

    m_TextColor = clrTextColor;
}

I hope the code is pretty much self explanatory.

Now some of the overridden methods and what they do.
Code: Cpp

/////////////////////////////////////////////////////////////////////////
/// <b>Function: PreSubclassWindow</b>
///
/// \param  NONE
///
/// \return void
///
/// \remarks    PreSubclassWindow to make the button is Owner Draw.
///
/////////////////////////////////////////////////////////////////////////
void CGuiButton::PreSubclassWindow()
{
    CButton::PreSubclassWindow();

    // Modifying the style to OwnerDraw
    ModifyStyle(0, BS_OWNERDRAW );

}


/////////////////////////////////////////////////////////////////////////
/// <b>Function: OnEraseBkgnd</b>
///
/// \param  pDC   (in\out)
///
/// \return BOOL
///
/// \remarks    We do not want the base class to erase the background.
///
/////////////////////////////////////////////////////////////////////////
BOOL CGuiButton::OnEraseBkgnd(CDC* pDC)
{
    // Do not erase background to be transparent
    return true;
}


/////////////////////////////////////////////////////////////////////////
/// <b>Function: OnKillFocus</b>
///
/// \param  pNewWnd   (in)
///
/// \return void
///
/// \remarks    Validates the button so that the Focus rect is removed
///             correctly
///
/////////////////////////////////////////////////////////////////////////
void CGuiButton::OnKillFocus(CWnd* pNewWnd)
{
    this->Invalidate();
}

and each of them is well documented.

Now the main function DrawItem
Code: Cpp

/////////////////////////////////////////////////////////////////////////
/// <b>Function: DrawItem</b>
///
/// \param  lpDrawItemStruct  (in\out)
///
/// \return void
///
/// \remarks    Draws the button in 3 steps
///             1. Bitmap     - Draws the loaded bitmap
///             2. Text       - Draws the button text
///             3. Focus Rect - Draws the focus rect of the button
///
/////////////////////////////////////////////////////////////////////////
void CGuiButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    ASSERT (lpDrawItemStruct);

    CDC btnDC ;
    btnDC.Attach(lpDrawItemStruct->hDC);    // get device context

    CBitmap* pbitmapDC=NULL;
    BITMAP bmpStruct;

    CRect btnRect;
    GetClientRect(&btnRect);

    // --------------------------------------
    // Draw the bitmap
    // --------------------------------------
   
    // Get the correct Bitmap
    if(! IsWindowEnabled())
        pbitmapDC=&m_DisabledBitmapDC;
    else
        pbitmapDC=&m_NormalBitmapDC;
   
    // Select the bitmap into a Compatible DC
    CDC *bmpDC = new CDC();
    bmpDC->CreateCompatibleDC(&btnDC);
    bmpDC->SelectObject(pbitmapDC);

    if(pbitmapDC != NULL)
    {
        pbitmapDC->GetBitmap(&bmpStruct);
        const int iDiff = 1;
        // Draw the bitmap on the button leaving one pixel from each side of the button
        btnDC.StretchBlt(iDiff, iDiff, btnRect.Width()-(2*iDiff), btnRect.Height()-(2*iDiff),bmpDC,0,0,bmpStruct.bmWidth,bmpStruct.bmHeight, SRCCOPY );
    }

    // --------------------------------------
    // Draw the Text
    // --------------------------------------

    CString sCaption;
    GetWindowText(sCaption);    // get button text

    int iLength = sCaption.GetLength();

    CRect textRect;
    textRect = lpDrawItemStruct->rcItem;

    int       oldMode = btnDC.SetBkMode(TRANSPARENT);
    COLORREF oldColor = btnDC.SetTextColor(m_TextColor);

    CSize sz;
    sz = btnDC.GetTextExtent(sCaption);
 
    BOOL bNoOfLines = FALSE;
    UINT uiDrawTextFormat = DT_CENTER|DT_VCENTER|DT_SINGLELINE;
   
    int iOffset = btnDC.DrawText(sCaption,textRect,uiDrawTextFormat);
   
   
    // --------------------------------------
    // Draw the Focus Rect
    // --------------------------------------
    if( (iLength)  && (lpDrawItemStruct->itemState & ODS_FOCUS) )
    {
        CRect focusRect( btnRect );
        focusRect.InflateRect(-1,-1,-1,-1);
        btnDC.DrawFocusRect(&focusRect);
    }

    btnDC.SetTextColor(oldColor) ;
    btnDC.SetBkMode(oldMode) ;
    btnDC.Detach() ;   
   
}

Its also well explained and here is the quote from the comment
Quote:

Originally Posted by Comment
Draws the button in 3 steps
1. Bitmap - Draws the loaded bitmap
2. Text - Draws the button text
3. Focus Rect - Draws the focus rect of the button

You can download the attached sample and run the program.

shabbir 1Dec2007 17:57

Re: Custom Image Button
 
I have reported the article for Nominate your favorite article of the month for November 2007. Add your nominations as well.

skynetto 12Jan2008 18:29

Re: Custom Image Button
 
any chance of using an external image with LoadImage? SetSkin is expecting an UINT and LoadImage gives me a HANDLE or at least a HBITMAP

skynetto 12Jan2008 18:35

Re: Custom Image Button
 
Quote:

Originally Posted by skynetto
any chance of using an external image with LoadImage? SetSkin is expecting an UINT and LoadImage gives me a HANDLE or at least a HBITMAP

OK got just have to modify what setskin is expecting of and change the LoadBitmap reference on guibutton.cpp

sampathkambar 25Jan2008 19:14

Re: Custom Image Button
 
What if,i want that button to be created dynamically..... what shall i do at that time.
Thanks in advance...

shabbir 25Jan2008 20:37

Re: Custom Image Button
 
Just make the object of the Custom button and specify the property as and when needed.

CasualProgrammer 10Jul2009 21:59

Re: Custom Image Button
 
Hello -

Is there a later release of this?

In GuiButton.cpp at line 229 (or so), there's:

CDC *bmpDC = new CDC();

But there is no corresponding "delete bmpDC" from that point to the end of the function. This produces a small (what, 16-byte?) memory leak each time the button is pressed.

Casual

nasko700 22Sep2009 11:34

Re: Custom Image Button
 
Hi! I find that if you drag the window (where is also your imageButton) out of the monitor's sizes and then drag it back, the image is not there anymore. I think, I have to use serialization, or?

sammor 2Aug2010 11:05

Re: Custom Image Button
 
HI,
I have 6 buttons with images,
when I launch the application, no problems,
when I click on some buttons, some Buttons disappear.
I am using it in CE 6.00 environment
Thanks

shabbir 2Aug2010 11:35

Re: Custom Image Button
 
Quote:

Originally Posted by sammor (Post 71063)
HI,
I have 6 buttons with images,
when I launch the application, no problems,
when I click on some buttons, some Buttons disappear.
I am using it in CE 6.00 environment
Thanks

May be some paint issues.


All times are GMT +5.5. The time now is 13:10.