• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 546
  • Last Modified:

Make some part of the ComboBox item bold

Hi, I am new with MFC. I have a ComboBox that has 6 fix items. Each item is a sentence. I would like to make one word in each item bold. Can you please lead me to a complete code example.

Details:
The ComboBox is used for a search. An Item can be: Search "all of the words" or "any of the words". I want to have the words "all" or "any" to be bold.

thanks.
0
Habben
Asked:
Habben
  • 2
1 Solution
 
CatalepsyCommented:
I believe the way you have to do this is make the CComboBox owner draw.  Then you have to create a class who's base class is type CComboBox.  Then you must put your drawing code in the OnDrawItem method.  You will have to draw each item, that is each line yourself; basically the draw item method is called once per item, unlike an OnDraw method where you draw everything at once..  This means you will have to have two fonts, one that is bold and one that is not and you will have to draw the string with 2 or 3 pDC->TextOut() calls.  Also, when you use class wizard to create an object for your Combo Box, you will need to go to the code that says it is of type CComboBox and change it to the name of your class.

Check out this MSDN link, also, for complete examples, search google for Owner draw combo box or owner draw list box.  The concept is the same, I believe you will get more hits on the list box.  I've done a few, I suppose if you wanted I could post some code for what OnDrawItem of mine looks like.  If you can do OnDraw, you can do this, it is just a couple more steps.  Also, make sure that you have the Owner draw drop down list set to Fixed or something like that, at least make sure it isn't No; this is in styles for the combo box's properties.

Good luck,
Catalepsy
0
 
CatalepsyCommented:
I believe the way you have to do this is make the CComboBox owner draw.  Then you have to create a class who's base class is type CComboBox.  Then you must put your drawing code in the OnDrawItem method.  You will have to draw each item, that is each line yourself; basically the draw item method is called once per item, unlike an OnDraw method where you draw everything at once..  This means you will have to have two fonts, one that is bold and one that is not and you will have to draw the string with 2 or 3 pDC->TextOut() calls.  Also, when you use class wizard to create an object for your Combo Box, you will need to go to the code that says it is of type CComboBox and change it to the name of your class.

Check out this MSDN link, also, for complete examples, search google for Owner draw combo box or owner draw list box.  The concept is the same, I believe you will get more hits on the list box.  I've done a few, I suppose if you wanted I could post some code for what OnDrawItem of mine looks like.  If you can do OnDraw, you can do this, it is just a couple more steps.  Also, make sure that you have the Owner draw drop down list set to Fixed or something like that, at least make sure it isn't No; this is in styles for the combo box's properties.

Just for the heck of it, I did owner draw for a list control, I will drop my .cpp file code in here so you can see it.  I tile a nice pretty bitmap across my list box, I will not include that code as you don't need it.  Other than that, it is for something like a chat server where the text shows up in color.  The color is embedded into the message.  The code is below.

COLORREF CMyListBox::DecipherColor(CString sColorSequence)
{
      COLORREF cColor = RGB(0, 0, 0);
      CString sColor;


      if (sColorSequence.GetLength() > 4)
      {
            sColor = sColorSequence.Mid(2, sColorSequence.GetLength() - 4);

            if (sColor.CompareNoCase("BLUE") == 0)
            {
                  cColor = BLUE;
            }

            else if (sColor.CompareNoCase("GREEN") == 0)
            {
                  cColor = GREEN;
            }

            else if (sColor.CompareNoCase("ORANGE") == 0)
            {
                  cColor = ORANGE;
            }

            else if (sColor.CompareNoCase("PURPLE") == 0)
            {
                  cColor = PURPLE;
            }

            else if (sColor.CompareNoCase("RED") == 0)
            {
                  cColor = RED;
            }

            else if (sColor.CompareNoCase("YELLOW") == 0)
            {
                  cColor = YELLOW;
            }
      }


      return cColor;
}

void CMyListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
      // TODO: Add your code to determine the size of specified item
      CClientDC   dc(this);
      TEXTMETRIC   tm;
      CFont* pFont = GetFont();
      CFont* pOldFont = dc.SelectObject(pFont);
      dc.GetTextMetrics(&tm);
      dc.SelectObject(pOldFont);
      lpMeasureItemStruct->itemHeight = tm.tmHeight + 4;      
}




///////////////////////////////////////////////////////////////////////////////
//  This is a class method that draws the requested string in the list box.
///////////////////////////////////////////////////////////////////////////////
void CMyListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
      CDC dc;
      CDC dcBitmapDC;
      COLORREF crTextColor = RGB(0, 0, 0);
      CRect rItemRectangle(lpDrawItemStruct->rcItem);
      CSize sSize;
      CString sItemText;
      DWORD dwX;
      PRINT_STRING psPrintString;
      UINT uiItemIndex = lpDrawItemStruct->itemID;


      //  Ensure the background bitmap is loaded
      if (m_pmbBackground == NULL)
      {
            m_pmbBackground = new CMyBitmap;

            m_pmbBackground->LoadBitmap("Background7.bmp");
      }

      //  Acqure a device context.
      dc.Attach(lpDrawItemStruct->hDC);
      dcBitmapDC.CreateCompatibleDC(&dc);

      //  As long as we are dealing with a valid item.
      if( uiItemIndex != (UINT) -1)
      {
            //  Get the item's text.
            GetText(uiItemIndex, sItemText);

            //  Set the text background mode to transparent.
            dc.SetBkMode(TRANSPARENT);

            //  Acquire the text color.
            crTextColor = GetItemData(uiItemIndex);

            //  Set the horizontal starting point for the text.
            dwX = rItemRectangle.left + 2;

            while (!sItemText.IsEmpty())
            {
                  //  Acquire the next string to pring.  This is necesarry because
                  //  a string may have embedded color sequences in it.  This allows
                  //  one item to be printed in a multitude of different colors.
                  psPrintString = ParseString(sItemText, crTextColor);

                  //  Set the text color.
                  dc.SetTextColor(psPrintString.cColor);

                  //  Print the text.
                  dc.TextOut(dwX, rItemRectangle.top + 2, psPrintString.sString);

                  //  Update the horizontal position for the next piece of text.
                  sSize = dc.GetTextExtent(psPrintString.sString);
                  dwX += sSize.cx;
            }
      }      

      //  Release the device context.
      ReleaseDC(&dcBitmapDC);
      dc.Detach();
}




///////////////////////////////////////////////////////////////////////////////
//  This is a class method that draws the background for the list box.
///////////////////////////////////////////////////////////////////////////////
BOOL CMyListBox::OnEraseBkgnd(CDC* pDC)
{
      CBrush bBackgroundBrush;
      CBrush *pbOldBrush;
      CDC dcBitmapDC;
      RECT rClientRectangle;


      if (m_pmbBackground == NULL)
      {
            m_pmbBackground = new CMyBitmap;

            m_pmbBackground->LoadBitmap("Background7.bmp");
      }

      //  Get the area occupied by the list box.
      GetClientRect(&rClientRectangle);

      dcBitmapDC.CreateCompatibleDC(pDC);

      //  Create a solid brush for the background.
      bBackgroundBrush.CreateSolidBrush(BACKGROUND_COLOR);

      //  Load the background brush into memory.
      pbOldBrush = pDC->SelectObject(&bBackgroundBrush);

      //  Draw a filled rectangle in the client area.
      pDC->Rectangle(&rClientRectangle);

      //  Restore the previous brush, if this step is skipped the application
      //  may crash.
      pDC->SelectObject(pbOldBrush);


      m_pmbBackground->TileBitmap(pDC, &dcBitmapDC, rClientRectangle.left,
            rClientRectangle.top, rClientRectangle.right - rClientRectangle.left,
            rClientRectangle.bottom - rClientRectangle.top);

      
      ReleaseDC(&dcBitmapDC);

      return TRUE;
}




///////////////////////////////////////////////////////////////////////////////
//  This is a class method that parses the source string into chunks.  The
//  reason for parsing is that embedded color characters may be present in the
//  string.
///////////////////////////////////////////////////////////////////////////////
PRINT_STRING CMyListBox::ParseString(CString &sSource, DWORD dwColor)
{
      bool bColorSequenceFound = false;
      CString sColorString;
      int iEndingIndex;
      int iNextIndex;
      int iStartingIndex;
      PRINT_STRING psPrintString;
      
      iStartingIndex = sSource.Find(COLOR_SEQUENCE_START, 0);

      //  Check to see if we have the beginning of an embedded color sequence.
      if (iStartingIndex >= 0)
      {
            iEndingIndex = sSource.Find(COLOR_SEQUENCE_END, iStartingIndex + 2);

            //  If we have an ending of an embedded color sequence then we need
            //  to acquire the color.
            if (iEndingIndex >= 0)
            {
                  //  We have two different scenarios that can occur.
                  //  One, the color sequence is at the beginning of the string
                  //  meaning we should decipher the color sequence's color value
                  //  and get the string after it.
                  //  Two, a string is before the color sequence, so extract the
                  //  string and return the given color.
                  bColorSequenceFound = true;

                  if (iStartingIndex == 0)
                  {
                        //  Otherwise, extract the color and decipher it.
                        sColorString = sSource.Left(iEndingIndex + 2);
                        psPrintString.cColor = DecipherColor(sColorString);

                        iNextIndex = sSource.Find(COLOR_SEQUENCE_START, iEndingIndex);

                        //  Get up to the next color sequence.
                        if (iNextIndex >= 0)
                        {
                              psPrintString.sString = sSource.Mid(iEndingIndex + 2,
                                    iNextIndex - (iEndingIndex + 2));

                              sSource = sSource.Mid(iNextIndex);                              
                        }

                        //  Otherwise, get the rest of the string.
                        else
                        {
                              psPrintString.sString = sSource.Right(
                                    sSource.GetLength() - (iEndingIndex + 2));

                              sSource = "";
                        }
                  }

                  else
                  {
                        psPrintString.sString = sSource.Left(iStartingIndex);
                        psPrintString.cColor = dwColor;

                        //  Shorten the source string by removing the string before
                        //  the color sequence.  This is a must as the calling method
                        //  runs a loop printing sections of the string until it is
                        //  printed in its entirity.
                        sSource = sSource.Right(sSource.GetLength() - iStartingIndex);
                  }
            }
      }

      //  No color sequences were found so return what was given.
      if (!bColorSequenceFound)
      {
            psPrintString.sString = sSource;
            psPrintString.cColor = dwColor;

            //  So that we don't continue to process this string we must
            sSource = "";
      }


      return psPrintString;
}

The method titled MeasureItem is very important as it tells MFC how tall each line in your combo box will be.  Make sure to implement it.

Good luck,
Catalepsy
0
 
HabbenAuthor Commented:
Sorry to answer late, I was gone for a while.

I could prefer and be more happy with a CComboBox-related code, but life can't be so easy allways :-)
Thanks.
0

Featured Post

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now