?
Solved

Make some part of the ComboBox item bold

Posted on 2003-03-28
3
Medium Priority
?
514 Views
Last Modified: 2013-11-20
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
Comment
Question by:Habben
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 2
3 Comments
 
LVL 3

Expert Comment

by:Catalepsy
ID: 8227579
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
 
LVL 3

Accepted Solution

by:
Catalepsy earned 320 total points
ID: 8227609
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
 

Author Comment

by:Habben
ID: 8325875
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

Want to be a Web Developer? Get Certified Today!

Enroll in the Certified Web Development Professional course package to learn HTML, Javascript, and PHP. Build a solid foundation to work toward your dream job!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.

752 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question