mrwad99
asked on
Owner draw tab control: emboldened text problem
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.CreateFon tIndirect( &lf)); // create the font
}
void CMyTabCtrl::DrawItem(LPDRA WITEMSTRUC T 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_BTNFAC E));
// Keep this order to prevent rollover effect occuring on active tab !
if (bSelected) {
pDC->SelectObject(m_TabFon t);
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
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.CreateFon
}
void CMyTabCtrl::DrawItem(LPDRA
{
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_BTNFAC
// Keep this order to prevent rollover effect occuring on active tab !
if (bSelected) {
pDC->SelectObject(m_TabFon
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
ASKER
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 ?
m_wndMyTabCtrl.InsertItem(
m_wndMyTabCtrl.InsertItem(
m_wndMyTabCtrl.InsertItem(
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 ?
> 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_TabFon t);
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
}
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_TabFon
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
}
Have you seen tab controls at codeproject?:
http://www.codeproject.com/tabctrl/AMCustomTabCtrlDemo.asp
http://www.codeproject.com/tabctrl/customtab.asp
http://www.codeproject.com/tabctrl/AMCustomTabCtrlDemo.asp
http://www.codeproject.com/tabctrl/customtab.asp
ASKER
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.
?
Really long tab t...
as opposed to
Really long tab title
How is the question.
?
ASKER
Points doubled.
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
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_CTabCtrl.3a3a.SetMinTabWidth.asp
ASKER
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.
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.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
ASKER
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 :)
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 :)
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.
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.
ASKER
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.
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.
Thanks, for the points, glad to be useful.
BR,
Jaime.
BR,
Jaime.
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.
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.
ASKER
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 !
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 !
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
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
ASKER
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.
Thanks.
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.