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.

sammor 3Aug2010 05:21

Re: Custom Image Button
 
what do u mean by paint issues,
The image is a BMP format created by Paint as 24-bit bitmap. is something wrong with that?

shabbir 3Aug2010 08:37

Re: Custom Image Button
 
No but to use any image as control you need to paint that image in the Paint message handler.

sammor 3Aug2010 12:21

Re: Custom Image Button
 
I paint the images in the paint message handler,
when launching, all the images are showing, then when clicking on one, others disappear

shabbir 3Aug2010 13:00

Re: Custom Image Button
 
It actually means there is some issue with painting and try moving the window and see if it comes back again

ganesh kumar 10Oct2010 15:18

Re: Custom Image Button
 
Hi all,
I could not find the GuiButton.h and GuiButton.cpp from the zip file. Could any give me the proper file.

shabbir 10Oct2010 18:07

Re: Custom Image Button
 
Quote:

Originally Posted by ganesh kumar (Post 73604)
Hi all,
I could not find the GuiButton.h and GuiButton.cpp from the zip file. Could any give me the proper file.

Then what did the zip file contain?

ganesh kumar 11Oct2010 14:34

Re: Custom Image Button
 
Hello shabbir,
When i open the zip file, it contain GuiButton.file. I cannot open that file.

shabbir 11Oct2010 16:10

Re: Custom Image Button
 
I re-downloaded the stuff and things work normal for me. If you have issues PM me your email address and I will try sending you the files to your email address.

ganesh kumar 12Oct2010 07:20

Re: Custom Image Button
 
Hello shabbir,
Here is my email address: blackjack1hk@yahoo.com.
Thanks for your kind help.

shabbir 12Oct2010 08:05

Re: Custom Image Button
 
Sent and do let me know if you still have any issues.

Skezza 4Jul2012 14:58

Re: Custom Image Button
 
Hello,
I know this thread is 2 years old but I was sent the link by a colleague who is learning WinCE 6 development. He was having problems using more than one CGuiButton. They were disappearing rather inexplicably. For example, pressing on one, then another would remove the bitmap from the first button.

I ran through the code on my lunch break at work and have found the cause:

Code:

void CGuiButton::OnKillFocus(CWnd* pNewWnd)
{
        this->Invalidate();
}

line 139 of GuiButton.cpp : this->Invalidate(); is unnecessary in my opinion.

My own experience is fairly middle of the road, but I just wondered why it was there? I cannot see a reason to call Invalidate() on the CGuiButton on kill focus. The only reason to call Invalidate is if the region needs repainting, but for a Bitmap button, I can't see when this would be the case.
Rather than say this fixes it (it does in my case) I was wondering if you could explain why it was there in the first place as I'm sure it isn't there for nothing?

Cheers

Skezza 4Jul2012 15:01

Re: Custom Image Button
 
For those who aren't sure, comment out the line and try again.


All times are GMT +5.5. The time now is 21:59.