Link to home
Start Free TrialLog in
Avatar of Karrtik Iyer
Karrtik IyerFlag for India

asked on

C++ | MFC | CMFCToolbar | Set tool button image as EMF file

Hi Experts,

I would like to know how can I set an EMF file on a disk as image to the CMFCToolBarButton's image.
We have the images of the tool bar buttons given as emf file which we are not supposed to convert to BMP and use it.
Instead we are suppose to directly use the EMF file to set as Tool bar button's image.

Please help and advise.

Thanks,
Karrtik
Avatar of sarabande
sarabande
Flag of Luxembourg image

the class  CMFCToolBarButton is defined in afxtoolbarbutton.h and implementation is in afxtoolbarbutton.cpp.

the class has virtual member function OnDraw, so you could derive from it and use an overloaded OnDraw to draw .emf files instead of one bitmap file containing all toolbar button images.

I would assume it is simpler to convert to bitmap but you may make up your own decision.

Sara
Avatar of Karrtik Iyer

ASKER

Hi Sara,
I already tried this approach. I could derive my custom class from CMFCToolBarButton, however with this approach, two issues occur.
1> The InsertButton call on CMFCToolBar fails with instance of my custom class derived from CMFCToolBarButton. The create object call inside Insert function fails for my custom class.
CMFCToolBarButtonEx mybutton( MY_ID, -1, _T("My Tool") );                        
m_nToolBar.InsertButton(mybutton  );
2>  Also CMFCToolBarButton does not allow message map to defined for the derived class. The below code fails to compile:
BEGIN_MESSAGE_MAP(CMFCToolBarButtonEx, CMFCToolBarButton)
END_MESSAGE_MAP()

Thanks,
Karrtik
I forgot to update in my question that I could override the DrawButton function of CMFCToolBar and do a playMetaFile using DC object. However I was not sure about the limitation of this DrawButton approach. I would like to know if because of using this DrawButton option, will it cause any default behavior provided by CMFCToolBarButton to get overridden except the image being redrawn, also are there any chances of memory or performance issues?

Sample code:
BOOL CMFCToolBarEx::DrawButton(
      CDC* pDC,
      CMFCToolBarButton* pButton,
      CMFCToolBarImages* pImages,
      BOOL bHighlighted,
      BOOL bDrawDisabledImages
      ){
if(pButton->m_nID == MY_ID){
                  HENHMETAFILE hMetaFile = NULL;
                  hMetaFile = ::GetEnhMetaFile(L"C:\\scan_dash_alert_d.emf");
                  BOOL retval = pDC->PlayMetaFile(hMetaFile,pButton->Rect());      
                  return retval;
            }
else
                  return CMFCToolBar::DrawButton(pDC,pButton,pImages,bHighlighted,bDrawDisabledImages);
}
(1) i would assume that InsertButton is not a virtual function (i will verify that tomorrow). so you better would provide an empty or dummy bitmap and only use the OnDraw to get what you want.
(2) between BEGIN_MESSAGE_MAP and END_MESSAGE_MAP you would define an variable sized array by means of macros like ON_MESSAGE(...), .... i would assume that an empty array lets the compiler complain. beside of that, you should try to go without a message map cause this is designed for customizing of classes which belong to the mfc framework and less for tool helpers.

Sara
ASKER CERTIFIED SOLUTION
Avatar of Zoppo
Zoppo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Sara,

InsertButton calls fails at the below location (afxtoolbar.cpp): The button pointer returned is NULL.
CMFCToolBarButton* pButton = (CMFCToolBarButton*) pClass->CreateObject();
      ENSURE(pButton != NULL);

And here is the declaration for InsertButton (it is virtual) from afxtoolbar.h:
virtual int InsertButton(const CMFCToolBarButton& button, INT_PTR iInsertAt = -1);

Thanks,
Karrtik
you need to overload the CreateObject function which is some kind of "virtual" constructor or "factory" code to creating derived objects rather than base class objects.

Sara
the pClass is of type CRuntimeClass*  what is a means to create objects from and get runtime info of CObject derived classes.

to make this feature available for your class you have to use the DECLARE_DYNCREATE macro in the header and the IMPLEMENT_DYNCREATE macro in the cpp file of your derived class.

Sara
About my previous comment: I forgot to mention the attached code uses Gdiplus, so you (if you don't use it yet) will have to initialize it. You can take a look at http://www.codeproject.com/Articles/1112/Starting-with-GDI to see how this can be done in a MFC app.

ZOPPO
Thanks Zoppo, I am trying your code.
Thanks Sara.
 I got that working by overriding DrawButton of the CMFCToolbar, does not necessarily have to override the CMFCToolBarButton::OnDraw, I guess.
The question would be say either on OnDraw or DrawButton I playing the EMF file works, however I am unable to get the text below the button working/appearing once I do the PlayMetaFile. How do I get to display the text below the EMF file using this approach?
See code below.
void CMFCToolBarButtonEx::OnDraw(
      CDC* pDC,
      const CRect& rect,
      CMFCToolBarImages* pImages,
      BOOL bHorz,
      BOOL bCustomizeMode,
      BOOL bHighlight,
      BOOL bDrawBorder,
      BOOL bGrayDisabledButtons
      )
{
      HENHMETAFILE hMetaFile = NULL;
      hMetaFile = ::GetEnhMetaFile(L"C:\\scan_dash_alert_d.emf");
      CRect myrect = rect;
      myrect.DeflateRect(rect.Width()/4,rect.Height()/4);
      BOOL retval = pDC->PlayMetaFile(hMetaFile,myrect);            
      if(retval == TRUE)
      {
            int i = i + 1;
      }
      this->m_strText = L"Scan Alert"; //This does not work
      
}
I guess I shall have to use the CDC and draw my own custom text and custom location. May be because of customised on draw the text set for button doesn't work in the default way as shown in my last post.
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial