Solved

Owner draw tab control: emboldened text problem

Posted on 2004-10-30
1,269 Views
Last Modified: 2013-11-20
Ah hello.

I have an owner draw tab control where the active tab's title is displayed in a bold, blue text.  The inactive tab's text is displayed in basic black text.  I initialise the bold font in the constructor, and redraw each tab appropriately as below.

m_TabFont is a CFont member of CMyTabCtrl.

CMyTabCtrl::CMyTabCtrl()
{
      LOGFONT lf;
      memset(&lf, 0, sizeof(LOGFONT));                  // zero out structure
      lf.lfHeight = 12;                              // request a 12-pixel-height font
      lf.lfWeight = FW_BOLD;
      strcpy(lf.lfFaceName, "MS Sans Serif");                  // request a face name "Arial"
      VERIFY(m_TabFont.CreateFontIndirect(&lf));            // create the font

}

void CMyTabCtrl::DrawItem(LPDRAWITEMSTRUCT lpdis)
{  
      const COLORREF BLUE = RGB(2, 30, 157);
      const COLORREF BLACK = RGB(0, 0, 0);
      const COLORREF RED = RGB(255, 0, 0);
      const COLORREF WHITE = RGB(255, 255, 255);
      const COLORREF LIGHT_BLUE = RGB(0, 136, 136);

      CRect rect = lpdis->rcItem;

      int nTabIndex = lpdis->itemID;
      if (nTabIndex < 0) return;

      BOOL bSelected = (nTabIndex == GetCurSel());
      
      char label[64];
      TC_ITEM tci;
      tci.mask = TCIF_TEXT;
      tci.pszText = label;
      tci.cchTextMax = 63;
      
      // Get all the relevant data into the TC_ITEM structure...
      if (!GetItem(nTabIndex, &tci)) return;

      CDC* pDC = CDC::FromHandle(lpdis->hDC);
      if (!pDC) return;
      int nSavedDC = pDC->SaveDC();

      pDC->SetBkMode(TRANSPARENT);
      pDC->FillSolidRect(rect, ::GetSysColor(COLOR_BTNFACE));

      // Keep this order to prevent rollover effect occuring on active tab !
      if (bSelected) {
            pDC->SelectObject(m_TabFont);
            pDC->SetTextColor(BLUE);
            pDC->DrawText(label, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
      } else {
            pDC->SetTextColor(BLACK);
            pDC->DrawText(label, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
      }

      pDC->RestoreDC(nSavedDC);
}

The problem I am having is that when a tab becomes active, sometimes the text will be too big to fit on the tab, so it is not fully visible, due to being emboldened.  I cannot see how to make the width of the tab bigger to accomodate this.  I thought I could use GetTextExtent() somehow, but even so I don't know if this would work for emboldened text or how to adjust the tab's width manually.

How can I do this ?

TIA
0
Question by:mrwad99
    18 Comments
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    Here is a dirty trick,
    Name all tabs with a whitespace at the end of each label, this will leave enough space to all tabs when them are bolded, and will avoid you to resize tabs.
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Hmm, I did

          m_wndMyTabCtrl.InsertItem(0, _T("This is tab one       "), 0);
          m_wndMyTabCtrl.InsertItem(1, _T("This is tab two       "), 0);
          m_wndMyTabCtrl.InsertItem(2, _T("This is tab three with a very long title    "), 0);

    where m_wndMyTabCtr is the tab control, and this does not make any difference.  The space is included when the tab is highlighted, hence some of the text is still missing.  Is that not what you meant to do ?
    0
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    > The space is included when the tab is highlighted, hence some of the text is still missing
    My intention is to make whitespaces disappear. I see you don't specify a font for default tab, maybe both differ not only in bold style:

     // Keep this order to prevent rollover effect occuring on active tab !
         if (bSelected) {
              pDC->SelectObject(m_TabFont);
              pDC->SetTextColor(BLUE);
              pDC->DrawText(label, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);    // This line could be outside if/else
         } else {
              // Missing font here, I suggest you to create a font for normal case too
              pDC->SetTextColor(BLACK);
              pDC->DrawText(label, rect, DT_SINGLELINE | DT_VCENTER | DT_CENTER);    // This line could be outside if/else
         }



    0
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Yeah I have seen those two links above, but am learning on the job so to speak so I want to know how to get around this problem myself.  I created another font for when the tab is not active but that makes no difference.  What I really want to be able to do is just adjust the size of the tab, or decrease the length of the text being displayed, maybe append "..." to it if necessary, eg

    Really long tab t...

    as opposed to

    Really long tab title

    How is the question.

    ?
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Points doubled.
    0
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    If you want to resize tabs by yourself use GetTextExtent to calculate text width, and use SetMinTabWidth() to resize:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_CTabCtrl.3a3a.SetMinTabWidth.asp
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Yeah that is fine, but SetMinTabWidth will adjust the size of *all* of the tabs.  

    I have also been looking at some of the other tab control functions and it seems that all of them operate on *all* of the tabs; I just want to play with one at a time.  How can I call this function on just the concerned tab, i.e. the one that is getting the focus, hence the one that will have the emboldened text ?

    Thanks for the help so far.
    0
     
    LVL 55

    Accepted Solution

    by:
    You can do the inverse:
    Set default tab control font to a bold font.
    Since you are owner drawing your tabs, draw tab's text with a normal non-bold font with the exception of the highlighted tab, this will leave always the exact room for a bold text.
    0
     
    LVL 43

    Expert Comment

    by:AndyAinscow
    Have a customised header control.  In that trap the HDN_ITEMCLICK (other possibles HDM_GETITEMRECT, HDN_ITEMCHANGING) message.  Find out what the new width of the tab is to be with the bold font.  Then use GetItem/SetItem to set the new width (mask = HDI_WIDTH, cxy = new width, of the HDITEM structure).  You should also reset the width of the previously active tab
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Gentlemen.

    Apologies for the delay.  I have in fact found the solution for this problem.  After reading http://www.codeguru.com/Cpp/controls/controls/tabcontrols/article.php/c2237/

    "Since different weighted fonts will give different sized text, the larger of the fonts should be selected as the underlying font for the control so that the sizes of the tabs will be calculated correctly."

    This is exactly what Jaime stated above; this link merely showed me how to do it.  Hence, I intend to close this question shortly giving Jaime the full points.

    Andy:

    you (as always) have raised an interesting issue there - a header control ?!  If you would care to discuss this further I will award you more points for your individual effort.

    Thanks all :)
    0
     
    LVL 43

    Expert Comment

    by:AndyAinscow
    By all means award the points to Jaime if you adopt his suggestion.

    It was a (possibly silly) idea of having a owner draw header control instead of the tabcontrol.  I haven't actually tried it but with the header one could  modify the widths on the fly when another section of the header is clicked.  You would respond to the click on the header as you would the click on a tab control.
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Oh right, I see.

    Yeah, I suppose that would not be the same as having the tab controls really.  Well, the suggestion was there, and as always it is appreciated.
    0
     
    LVL 55

    Expert Comment

    by:Jaime Olivares
    Thanks, for the points, glad to be useful.
    BR,
    Jaime.
    0
     
    LVL 43

    Expert Comment

    by:AndyAinscow
    I had another thought  whilst walking the dog.

    Leave the fonts alone.
    For the active tab change the text dynamically and add say __ (just some characters that are not going to appear in the normal text).  The tab control will widen to cope with this.  When the active tab loses its active status then trim this text off and set back to the correct text.  This will narrow the tab to fit.
    Now when you draw your text just trim these characters off.

    This should result in each tab having a similar margin.  This patch with the font (I suspect) will have a number of tabs looking grotty with a large margin round the text compared to the active tab.
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Andy,

    I think what you are asking is similar to what Jaime suggested on 10/30/2004 07:35PM BST.  I did not notice any grottiness (?) on the tabs when using the selected method, but if you have any more suggestions then please post.

    Cheers !
    0
     
    LVL 43

    Expert Comment

    by:AndyAinscow
    I noted your response that the extra space was not allocated when Jaime suggested whitespace, I thought maybe windows is being clever and trimming the text.  Note I didn't suggest whitespace and I suggested only assigning the extra chars when the tab was set as the selected one (dynamically modifying the text, but you only display the 'real' text).


    Grottiness - I'll try to give you my mental picture of what you are describing.
    treat the | as the vertical line when the tabs are drawn. Text on tabs - first, selected, last

    Default font
    | first |ELECTE| last |      <----- truncated text

    set your large font for all
    |    first     | SELECTED |      last      |   <-------  large margins around text in tabs with the default font

    What I thought was that when the second tab is selected you dynamically change the text to eg selected___  The tab control will then resize to make it fit.  However when you draw the text you trim the rightmost ___ chars off and only display selected in you larger font BUT in a now oversized rectangle to result in
    | first | SELECTED | last |    <---- large font but similar left/right margins around each text
    0
     
    LVL 19

    Author Comment

    by:mrwad99
    Ah, I see what you are mentioning now AndyAinscow.  I must say that I have not experienced any of these problems as yet, but, if I do, I will try this suggestion and award points if the idea here works.

    Thanks.
    0

    Write Comment

    Please enter a first name

    Please enter a last name

    We will never share this with anyone.

    Featured Post

     Java Android Coding Bundle

    Whether you're an Apple user or Android addict, learning to code for the Android platform is an extremely valuable, in-demand skill. It all starts with Java, the language behind the apps and games that make Android the top platform it is today.

    Suggested Solutions

    Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
    Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
    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.
    Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…

    911 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

    Need Help in Real-Time?

    Connect with top rated Experts

    13 Experts available now in Live!

    Get 1:1 Help Now