Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Owner draw tab control: emboldened text problem

Posted on 2004-10-30
18
Medium Priority
?
1,321 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
Comment
Question by:mrwad99
[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
  • 8
  • 6
  • 4
18 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12453344
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
ID: 12453371
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
ID: 12453387
> 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
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12453405
0
 
LVL 19

Author Comment

by:mrwad99
ID: 12453471
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
ID: 12453473
Points doubled.
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12453506
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
ID: 12456483
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:
Jaime Olivares earned 1000 total points
ID: 12456747
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 45

Expert Comment

by:AndyAinscow
ID: 12461016
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
ID: 12504004
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 45

Expert Comment

by:AndyAinscow
ID: 12505408
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
ID: 12505450
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
ID: 12506582
Thanks, for the points, glad to be useful.
BR,
Jaime.
0
 
LVL 45

Expert Comment

by:AndyAinscow
ID: 12521349
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
ID: 12532591
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 45

Expert Comment

by:AndyAinscow
ID: 12532765
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
ID: 12575400
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

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

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. …
In this post we will learn different types of Android Layout and some basics of an Android App.
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.
In this video, Percona Solution Engineer Dimitri Vanoverbeke discusses why you want to use at least three nodes in a database cluster. To discuss how Percona Consulting can help with your design and architecture needs for your database and infras…

596 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