|
Hi,
one problem I have in understanding your code is why you have used 3 CRect structures for a simple operation such as getting the dimensions of a Tab Control ? Since your code doesnt have any comments on this regard and since its difficuilt for me to comprehend the code in context, I would like an explanation on the use of
// 1st paint the tab body
CRect rcPage,rcItem,rcClient;
Why have these rects funny names as in Page, Item and Client ?
Yes, I am a beginner in control programming.
thanx, hoping to hear an answer from you soon !
Eraj.
|
|
|
|
|
Hi,
Thanks for writing such wonderful code. I am new to VC++, i include XPTabCtrl in my project, everything seems to be alright until when i am pointing to other tabs there was no highlight as in the example. Can i know why is this happen to my project ? Is that any DLL i have to include ? By the way when i use it in multiline i found out that when i am clicking to upper tabs, the lower tab that i click before is highlight as well. Why is this happen ?
Thanks for your help.
David
|
|
|
|
|
Have you already implemented this tab control with edit option in tab items?
If you have implemented, could you send me the code source?
|
|
|
|
|
I tried to use the buttom style on XP. When there are more tabs than the tab control can showm the spin buttons appears. However, when I used the spin button to view from the beginning tab to the end tab and end tab to begining, the outline of previous tab are showed and it looks like there are extra tabs but there isnt'. Do you have ideas that I fix it? Or , anyway, I can detect the spin button is pressed? Any ideas?
| last tab | | | <spin buttons="">
------------ ----
Thanks for your helps.
|
|
|
|
|
Whenver I choose my tab style as vertical in the dialog editor, it does not show tab labels. This problem is not occured while setting this style in the code using ModifyStyle, but after doing that tab labels are not shown when XP Theme is not active.
|
|
|
|
|
Hi Im experiencing the same problem too.
Infact this is the same reason, we are unable to use this great control on a CWnd.
You gotta create this in a CDialog ( dialog designer ) and set the "Visible" value to False. Thereafter in code the ModifyStyle method should be called and only in here should the vertical style be set so as to let the control have vertical text !
Hope this issue / BUG gets resolved soon !
|
|
|
|
|
When runing the App with xp themes, the the first page in the app is blank until you click on the tab the it populates it with a dialogue, in win2K it displays the first page by default!
i call SetCurSel in OnInitDialog but still does the same?\
Has anybody had this problem?
|
|
|
|
|
I've noticed several people on the list discussing their patches but not
all of the patches have been posted. Is it possible to get them?
Thanks
|
|
|
|
|
I had a look at this thread last week and I study about using this class or write my own one...
During reading some stuff @ newsgroups I found a article abaout XP Style and controls.
So I decide to use Applname.manifest to do the work (only under Windows XP)
Now any Standart controls lookz XP-like...
To test U can create within U /res directoy a .manifest file (XML) if not exists already..
just add a resource in U resource.h file
#define IDR_MANIFEST 1
#define RT_MANIFEST 24
within U .rc2 file U add a line
IDR_MANIFEST RT_MANIFEST MOVEABLE PURE "res\appname.manifest"
If U appl. runs under W2K it uses the W2K standart controls under XP it used the new XP Controls.
For me the better solution to deal with XP....
Hope it helkps somebody
C'ya
|
|
|
|
|
Sorry, but you've completely missed the point. The manifest is indeed a prerequisite for using XP themes in applications. Without it, your app will just look like a normal Win2k app.
The problem here, however, is that the XP implementation of tab controls is buggy and doesn't support any orientations other than vertical-top.
|
|
|
|
|
When left or right and have many buttons, appear a vertival spin button.
but the vertical spin button are not active.
|
|
|
|
|
Line 266 in XPTabCtrl.cpp says:
"if(pcImg) delete pcImg;"
it should say:
"if(pcImg) delete [] pcImg;"
|
|
|
|
|
Here's a fix so that true color images can be displayed on the tabs
void CXPTabCtrl::InitImageList(UINT nBitmapID, int nImageCount/*=0*/)
{
if(!::IsWindow(GetSafeHwnd()) || m_ilTabs.operator HIMAGELIST()){
ASSERT(FALSE);
return;
}
CBitmap bitmap;
if(bitmap.LoadBitmap(nBitmapID)){
BITMAP bmp;
if(bitmap.GetBitmap(&bmp)){
if(!nImageCount)
nImageCount = bmp.bmWidth / bmp.bmHeight; // use square images
if(m_ilTabs.Create(bmp.bmWidth / nImageCount, bmp.bmHeight, ILC_COLORDDB | ILC_MASK , nImageCount, 1)){
m_ilTabs.Add(&bitmap, RGB(255,0,255)); // transparency color magenta
SetImageList(&m_ilTabs);
return; // ok
}
}
}
ASSERT(FALSE); // error
}
|
|
|
|
|
Hi,
The control is great on XP with themes enabled - just what I needed.
But I need the control in left orientation showing text (with or without themes), and as discussed below - the text shows up horizontal instead of vertical (with themes disabled).
Has anyone fixed this ????
Can anyone say why the text isn't rotated ???
AFAIK, the comctrl5 CTabCtrl *IS* able to rotate the label text. I used this when I was developing under Win2k before. Now I am developing under XP, switching back and forth between Classic and XP look to test the control.
Thanks,
Fred
|
|
|
|
|
Being new to C++ I am having a few problems adding a page to a tab.
I have previously used m_tabPages[0]->Create(IDD_TAB_ONE, this); under CTabCtrl.
But am unsure how to approach it now.
Any help is appreciated.
Regards
Steve Kelly
|
|
|
|
|
Same problem here from a beginners point of view
|
|
|
|
|
OK, my problem with the XPTabCtrl + MadButch patch was that it doesn't allow for owner-drawn tabs. However, the fix for this is not too difficult. The problem is that the DrawTabItem function assumes the standard case (text/image list). So we need to test for the owner-draw flag, and if activated, call DrawItem with the correct info, thusly:
void CXPTabCtrl::DrawTabItem(CDC* pDC, int ixItem, const CRect& rcItemC, UINT uiFlags)<br />
{<br />
if (GetStyle() & TCS_OWNERDRAWFIXED)<br />
{<br />
DrawOwnerDrawTabItem(pDC, ixItem, rcItemC, uiFlags);<br />
}<br />
else<br />
{<br />
}<br />
}<br />
<br />
void CXPTabCtrl::DrawOwnerDrawTabItem(CDC* pDC,int ixItem,const CRect& rcItemC,UINT uiFlags)<br />
{<br />
DRAWITEMSTRUCT dis;<br />
TCITEM tcitem;<br />
<br />
ASSERT(pDC);<br />
if (pDC)<br />
{<br />
dis.CtlID = GetDlgCtrlID();<br />
dis.CtlType = ODT_TAB;<br />
dis.hDC = pDC->m_hDC;<br />
dis.hwndItem = GetSafeHwnd();<br />
dis.itemAction = ODA_DRAWENTIRE;<br />
<br />
VERIFY(TabCtrl_GetItem(GetSafeHwnd(), ixItem, &tcitem));<br />
dis.itemData = tcitem.lParam;<br />
<br />
dis.itemID = ixItem;<br />
dis.itemState = ((uiFlags&2)? ODS_SELECTED:0); <br />
dis.rcItem = rcItemC;<br />
<br />
DrawItem(&dis);<br />
}<br />
}<br />
I hope I got the DRAWITEMSTRUCT stuff right. There may be some minor detail I missed.
This fixes the problem...almost. If your custom drawing in DrawItem is done via the DC passed via the DRAWITEMSTRUCT, you're fine. However, I have sinned because I don't do this. I create some custom controls on the tabs and they don't get passed the DC, they just repaint themselves. This means that they get overpainted by the code at the end of DrawThemesXpTabItem, which dumps the content of the MemDC into the window DC. So I have come up with an ugly patch for this. Improvements welcome.
What I do is simply flag the owner-draw case and delay the call to DrawTabItem to the end. I have to save the ixItem variable because it's changed afterwards and I didn't want to inquire too closely as to why.
void CXPTabCtrl::DrawThemesXpTabItem(CDC* pDC, int ixItem, const CRect& rcItem, UINT uiFlag) <br />
{
<br />
BOOL bBody =(uiFlag& 1)?TRUE:FALSE;<br />
BOOL bSel =(uiFlag& 2)?TRUE:FALSE;<br />
BOOL bHot =(uiFlag& 4)?TRUE:FALSE;<br />
BOOL bBottom=(uiFlag& 8)?TRUE:FALSE;
BOOL bVertic=(uiFlag&16)?TRUE:FALSE;
BOOL bLeftTab=!bBottom && bVertic && !bBody;<br />
<br />
bool bDelayDrawItem = ((GetStyle() & TCS_OWNERDRAWFIXED) != 0);<br />
int ixDelayItem = -1;<br />
<br />
CSize szBmp=rcItem.Size();<br />
if(bVertic) SwapVars(szBmp.cx,szBmp.cy);<br />
<br />
...<br />
<br />
if(bVertic)<br />
{ if(bBody || !bBottom) bihOut.biHeight=-szBmp.cy;<br />
if(!bBottom && !bBody && ixItem>=0)
{ if(bSel) rcMem.bottom--;<br />
<br />
if (!bDelayDrawItem)<br />
{<br />
DrawTabItem(&dcMem, ixItem, rcMem, uiFlag);<br />
}<br />
else<br />
{<br />
ixDelayItem = ixItem;<br />
}<br />
ixItem=-1;<br />
} }
...<br />
<br />
if(!bBody && ixItem>=0)
{ if(bSel) rcMem.bottom--;<br />
<br />
if (!bDelayDrawItem)<br />
{<br />
DrawTabItem(&dcMem, ixItem, rcMem, uiFlag);<br />
}<br />
else<br />
{<br />
ixDelayItem = ixItem;<br />
}<br />
<br />
if(bVertic)
{ bihOut.biHeight=-szBmp.cy;<br />
GetDIBits(*pDC, bmpMem.operator HBITMAP(),nStart,szBmp.cy-nLenSub,pcImg,&biOut,DIB_RGB_COLORS);<br />
} }<br />
<br />
...<br />
<br />
pDC->BitBlt(rcItem.left,rcItem.top,szBmp.cx,szBmp.cy,&dcMem,0,0,SRCCOPY);
dcMem.SelectObject(pBmpOld);<br />
<br />
if (bDelayDrawItem && ixDelayItem != -1)<br />
{<br />
DrawTabItem(&dcMem, ixDelayItem, rcMem, uiFlag);<br />
}<br />
}<br />
Well, it's not pretty but it's working for me at the moment. I'll keep you posted.
|
|
|
|
|
Alas, all is not well with my fix. I've discovered that it can cause nasty random crashes. Well, not random really. "Random" means "whose cause I do not yet understand".
I'm looking into it.
|
|
|
|
|
OK, I think I fixed it. Apart from the prudent addition of a call to ZeroMemory, which I shouldn't have omitted, the only change is to omit passing lParam from TCITEM to itemData in DRAWITEMSTRUCT. It now seems clear that this is *NOT* what you are supposed to do. Apparently you just use the lParam data for your purposes in other tab control functions. But I haven't been able to dig up much information on the use of itemData either; the documentation only mentions its use in the case of combos and lists.
All that's needed is to replace my original version of DrawOwnerDrawTabItem with this one:
<br />
void CXPTabCtrl::DrawOwnerDrawTabItem(CDC* pDC,int ixItem,const CRect& rcItemC,UINT uiFlags)<br />
{<br />
DRAWITEMSTRUCT dis;<br />
<br />
ASSERT(pDC);<br />
if (pDC)<br />
{<br />
ZeroMemory( (void *)&dis, sizeof(DRAWITEMSTRUCT) ); <br />
dis.CtlID = GetDlgCtrlID();<br />
dis.CtlType = ODT_TAB;<br />
dis.hDC = pDC->m_hDC;<br />
dis.hwndItem = GetSafeHwnd();<br />
dis.itemAction = ODA_DRAWENTIRE;<br />
dis.itemData = 0;<br />
dis.itemID = ixItem;<br />
dis.itemState = ((uiFlags&2)? ODS_SELECTED:0); <br />
dis.rcItem = rcItemC;<br />
<br />
DrawItem(&dis);<br />
}<br />
}<br />
Have fun.
|
|
|
|
|
When resizing the tab, ghosting appears in the part of the screen where labels could be drawn (but are not). Let's say you have a tab control of 400 pixels wide, with 2 tabs under it, both 50 pixels wide. You would then have an area to the right (300 pixels wide) that would not be redrawn on resizing.
I wrote an "as flicker free as possible" solution for it, and here is the code:
(this is old code , and this is new code )
<br />
void CXPTabCtrl::OnPaint() <br />
{<br />
if(!IsExtendedTabTheamedXP())
{ Default(); return; } <br />
CPaintDC dc(this);
<br />
CRect rcClip; rcClip.SetRectEmpty();<br />
dc.GetClipBox(rcClip);<br />
<br />
CRect rcPage,rcItem,rcClient;<br />
GetClientRect(&rcPage);<br />
rcClient=rcPage;<br />
AdjustRect(FALSE,rcPage);<br />
<br />
switch(m_eTabOrientation)<br />
{ case e_tabTop: rcClient.top =rcPage.top -2; break;<br />
case e_tabBottom: rcClient.bottom=rcPage.bottom+3; break;<br />
case e_tabLeft: rcClient.left =rcPage.left -1; break;<br />
case e_tabRight: rcClient.right =rcPage.right +3; break;<br />
default: ASSERT(FALSE); return;<br />
}<br />
UINT uiVertBottm;<br />
uiVertBottm =(m_eTabOrientation&1)? 8:0;
uiVertBottm|=(m_eTabOrientation&2)?16:0;
UINT uiFlags=1|uiVertBottm;
DrawThemesXpTabItem(&dc, -1, rcClient,uiFlags);
<br />
int nTab=GetItemCount();
if(!nTab) return;
<br />
<br />
CRgn rgnItem;
CRgn rgnRepaintArea;
CRect rcRepaintArea;
<br />
VERIFY( GetItemRect( 0, &rcItem) );<br />
if( m_eTabOrientation == e_tabTop )<br />
{<br />
rcRepaintArea.top = rcItem.top - 2;
rcRepaintArea.bottom = rcItem.bottom;<br />
rcRepaintArea.left = rcClient.left;<br />
rcRepaintArea.right = rcClient.right;<br />
}<br />
else if( m_eTabOrientation == e_tabBottom )<br />
{<br />
rcRepaintArea.top = rcItem.top;<br />
rcRepaintArea.bottom = rcItem.bottom + 2;
rcRepaintArea.left = rcClient.left;<br />
rcRepaintArea.right = rcClient.right;<br />
}<br />
else if( m_eTabOrientation == e_tabLeft )<br />
{<br />
rcRepaintArea.top = rcClient.top;<br />
rcRepaintArea.bottom = rcClient.bottom;<br />
rcRepaintArea.left = rcItem.left - 2;
rcRepaintArea.right = rcClient.left;
}<br />
else if( m_eTabOrientation == e_tabRight )<br />
{<br />
rcRepaintArea.top = rcClient.top;<br />
rcRepaintArea.bottom = rcClient.bottom;<br />
rcRepaintArea.left = rcItem.left;<br />
rcRepaintArea.right = rcItem.right + 2;
}<br />
<br />
rgnRepaintArea.CreateRectRgnIndirect( rcRepaintArea );<br />
rgnItem.CreateRectRgn( 0, 0, 0, 0 );<br />
<br />
<br />
TCHITTESTINFO hti; hti.flags=0;<br />
::GetCursorPos(&hti.pt); ScreenToClient(&hti.pt);<br />
int ixHot=HitTest(&hti);<br />
int ixSel=GetCurSel();<br />
<br />
for(int ixTab=0; ixTab<nTab; ixTab++)<br />
{ if(ixTab==ixSel)<br />
continue;<br />
VERIFY(GetItemRect(ixTab, &rcItem));<br />
if(m_eTabOrientation==e_tabLeft) rcItem.right++;<br />
uiFlags=uiVertBottm|(ixTab==ixHot?4:0);
DrawThemesXpTabItem(&dc,ixTab,rcItem,uiFlags);<br />
rgnItem.SetRectRgn( rcItem );<br />
rgnRepaintArea.CombineRgn( &rgnRepaintArea, &rgnItem, RGN_DIFF );<br />
}<br />
VERIFY(GetItemRect(ixSel, &rcItem));
rcItem.InflateRect(2,2);<br />
if(m_eTabOrientation==e_tabTop) rcItem.bottom--;<br />
uiFlags=uiVertBottm|2;
DrawThemesXpTabItem(&dc, ixSel, rcItem,uiFlags);<br />
rgnItem.SetRectRgn( rcItem );<br />
rgnRepaintArea.CombineRgn( &rgnRepaintArea, &rgnItem, RGN_DIFF );<br />
<br />
HBRUSH hBrBack = (HBRUSH) ::GetClassLong( GetParent()->GetSafeHwnd(), GCL_HBRBACKGROUND );<br />
if( hBrBack == 0 )<br />
{<br />
hBrBack = ::GetSysColorBrush( COLOR_BTNFACE );<br />
}<br />
dc.FillRgn( &rgnRepaintArea, CBrush::FromHandle( hBrBack ) );<br />
}<br />
|
|
|
|
|
Hi
Nice work. Just one thing - it seems like you forgot to finish the left/right orientation bit. You've left two lines commented:
and it looks as though you realised that the code before it would be valid for all orientations, but then forgot to remove the previous if statement:
if( ( m_eTabOrientation == e_tabTop ) ||<br />
( m_eTabOrientation == e_tabBottom ) )<br />
As a result, if you have left or right tabs, there's a very nasty crash indeed .
I think the solution is to remove that condition and then add code to subtract 2 from the left or right sides, depending on the orientation. I'm not sure whether there's anything else missing. I have to do some more tests.
Also, I'm not sure what I'll have to do to get this working with my tab control class, because I've overridden the DrawItem function to place controls on each tab, and it seems like this implementation just takes over the drawing completely. Anybody got any hints? I'll look at it tomorrow in any case.
|
|
|
|
|
Oops
I left it open since I wasn't using left or right aligned tabs anywhere, but I didn't mean for it to crash. And I was fixing this during crunch time, you know how work pressure can be
I will see if I can throw a look at it tomorow.
Sorry
|
|
|
|
|
It's pretty simple - if I remember correctly (I don't have the code in front of me), there is a rect which is uninitialised in the case of left/right, and later that's used to create a region, which fails (the BOOL is not checked though) and then that invalid region is used somewhere, and bad things happen.
If you don't fix it first I'll send my corrections, which seem to have fixed it OK.
Meanwhile let me know if you happen to be the world's leading expert in how the work is divided up between DrawItem and OnPaint in the tab control, because I think I'll have to dive into that tomorrow
Cheers
|
|
|
|
|
I modified the original post, so it includes the fix. Plus I cleaned the code up some more, with better variable names and comments.
What I do notice is that in my example code, the tab labels (with just text on them) are not drawn correctly, because the text on them isn't rotated. Not sure why
And I'm unfortunately not the worlds leading expert on DrawItem and Repaint I'm not sure what modifications you have, but you could make the DrawTabItem function of the CXPTabCtrl store the rectangles/settings for each Tab label, and then ask those regions from the CXPTabCtrl and do your own drawing inside them.
good luck
|
|
|
|
|
Good stuff, that certainly fixes the problem. Thanks!
OK, now I will try to do battle with DrawItem...
|
|
|
|
|