|
The scenario:
If the tab control is placed on the top via obj.GetTabCtrl().ModifyStyle(CTCS_BOTTOM, 0); then the child views to the tab control don't draw correctly on the bottom. The child view is not shifted down in respect to the tab control, leaving an undrawn strip on the bottom where the tab control would have been if the style wasn't changed.
Pressing another tab doesn't change anything until the original tab is pressed again, in which case the child view shifts down to the correct postion. Sizing the window causes the child view to shift back up again to the incorrect position.
|
|
|
|
|
With the Common Control tab control, the control takes up the entire client area of the parent, and any "views" are children of the tabs. So when you switch between having the tabs on the top or bottom, the tab control itself completely deals with this.
With CCustomTabCtrl derived tab controls, the control doesn't take up the entire client area of the parent, only the part needed to render the tabs. Any "views" are *not* children of the tab control. It's up to the parent to determine and update the size (width, height) and position (top, bottom, bottom left, etc.) of the tab control and other children. So its actually the parent that asks about the CTCS_BOTTOM style from the tab control. Its also the parent who can do the "switching" of active child windows - the tab just sends notifications that the parent uses to figure out what to do when.
By having the parent manage the size and position of the tab control, you could do an Excel style tab control, with the tabs to the left along side the bottom scrollbar with a splitter in-between. I don't currently have any samples that show this. You could also have the parent put the tabs right in the middle of the window, make them take up half the height of the window, put it in a 50x50 area in the top right corner, etc. - it's up to the parent.
ModifyStyle is basically just an ATL::CWindow wrapper around calling ::SetWindowLong(..., GWL_STYLE, ...). Most of the tab control styles are used directly by the tab control itself, and so when the style changes, it can deal with it (handling WM_STYLECHANGING, WM_STYLECHANGE). However, since CTCS_BOTTOM is actually used by the parent, you need to be sure that the parent gets a chance to resize, reposition, and redraw everything appropriately when this style is changed. The tabs might be sized and positioned slightly differently with different parents (MDI tabs versus TabbedFrame, etc.), so the tab control itself can't make any assumption about how to do this - its up to the caller that modified CTCS_BOTTOM.
You can often get away with calling ModifyStyle to toggle CTCS_BOTTOM on the tab control right after it's created without having to worry about resizing, repositioning, and redrawing, etc.. But if you call it when tabs are already present, then it's up to the caller to do anything else necessary for the parent to resize, reposition, and redraw correctly.
I had thought that people would usually just make a choice beforehand about whether their tabs showed up on top or bottom, and do that during or just after tab creation. The base "CCustomTabOwnerImpl" exposes this through the "CreateTabWindow" call. If you're using one of the out-of-the-box CTabbedFrameImpl derived classes I've provided (CTabbedPopupFrame, CTabbedChildWindow), there currently isn't a really good way of setting different styles. You could have your own CTabbedFrameImpl derived class, and handle WM_CREATE yourself, calling CreateTabWindow with the tab styles you want.
I also haven't exposed a nice method for toggling whether it shows on the top or bottom if you already have added some tabs and need the parent to resize, reposition and redraw. If this is something you want to do, I can maybe add something to the various "tab parent" windows I provide (CCustomTabOwnerImpl and derived classes) to do this.
-Daniel
|
|
|
|
|
I was orginally using the CTabbedChildWindow. I took it and created CTopTabbedChildWindow and overrided the WM_CREATE message then called CreateTabWindow(m_hWnd, rcDefault, CTCS_TOOLTIPS). To my dismay I got the same issue where the child views (not the tabs themselves) would draw under the Tab Control Bar. It seems that the tab control isn't shifting the view properly the first time, but it will when you change the tab then go back. That leads me to believe that there is something going wrong with the TabbedFrame because it will eventually draw the child window in the right position.
I am currently going through the code to see if I can find the bug but since the library is so big it might take some time.
After some digging, I think the problem is with
void TabbedFrameImpl::UpdateLayout(BOOL bResizeBars = TRUE)
...
if(m_hWndActive)
{
::DeferWindowPos(
hdwp,
m_hWndActive,
NULL,
rect.left, rect.top + m_nTabAreaHeight,
rect.right - rect.left,
rect.bottom - (rect.top+m_nTabAreaHeight),
SWP_NOZORDER | SWP_SHOWWINDOW);
}
...
It looks like this code should be drawing m_hWndActive just below the Tab Bar but it isn't. Now I could be way off on my prognosis here but maybe it's the issue.
|
|
|
|
|
clintsinger wrote:
After some digging, I think the problem is with ...
If you look at the entire function, you'll see the lines:
HDWP hdwp = BeginDeferWindowPos(nWindowPosCount);
DWORD dwStyle = (DWORD)m_TabCtrl.GetWindowLong(GWL_STYLE);
BOOL bHasBottomStyle = (dwStyle & CTCS_BOTTOM);
if(bHasBottomStyle)
{
...
with the part you referenced above as part of the "else".
Then after that "if" statement is
m_TabCtrl.UpdateLayout();
So if there is an issue, its somewhere else
-Daniel
|
|
|
|
|
If I call m_tabCtrl.UpdateLayout (where m_tabCtrl is a CTabbedChildWindow< CDotNetTabCtrl<CTabViewTabItem> >) from my main OnSize then the view positions correctly, even with the tabs on the top. Unfortunately it looks like it the view jumps between the wrong position and the right position. Also clicking one of the tabs resets the child view to the wrong postion (only after an OnSize), until the tab another tab is clicked then the orginal is clicked back again.
|
|
|
|
|
clintsinger wrote:
it looks like it the view jumps between the wrong position and the right position
I can't seem to reproduce this behavior. For example, if I modify CTabbedFrameImpl::OnCreate to call
CreateTabWindow(m_hWnd, rcDefault, CTCS_TOOLTIPS)
instead of
CreateTabWindow(m_hWnd, rcDefault, (CTCS_BOTTOM | CTCS_TOOLTIPS))
the tabs show up on top like they're suppose to, and the child views are positioned correctly. Switching the tabs doesn't make it "jump" at all.
If you can send me directly a sample that demonstrates the problem you're seeing, I'll look into it.
P.S. For the next update, I'm going to update CTabbedFrameImpl so that you can tell it what tabs styles to use when creating the tab control, so that you get to choose a little easier.
-Daniel
|
|
|
|
|
I'm programming in MFC and I whould like use those set of classes in my current project. Can anyone help me to use those in MFC or insert in a separated DLL?
Are there another ways?
Thank you for help me.
Massimo Germi
|
|
|
|
|
Yes, it seems a couple of people would like to use these tabs in an MFC app. If you just want to use an existing tab control (say, like CDotNetTabCtrl) similar to how you use a SysTreeView32 or SysListView32, one way is to setup a Win32 DLL that uses ATL/WTL, then expose DLL functions to access the functionality of the tab control. Another way (that I haven't tried) is to ATL/WTL "enable" your MFC app, and use the tab control class directly.
If you want to use the tab control for doing some of the tabbed MDI or tabbed frame stuff, those classes are written to work with the ATL style of windowing and ATL/WTL base classes (such as CMDIFrameWindowImpl, etc.) used in ATL/WTL apps. These would need to be ported to work in the MFC framework and style of doing windowing.
Of course, the best choice is just to dump MFC completely and come over to the ATL/WTL party
-Daniel
|
|
|
|
|
...provide some classes that let the user drag and drop tabbed views between docking windows... like in .net
That's be really handy!
|
|
|
|
|
Yes, that's on my TODO list. Sergey Klimov has already written a sample called "SDITabbedSample" that uses my tab stuff that let's you drag and drop tabbed views. It's with the demo apps for his WTLDockingWindow stuff.
-Daniel
|
|
|
|
|
I just wanted to say thanks. I really appreciate the hard work that people put into all these libraries to help us little folks out.
|
|
|
|
|
I second that, you guys are doing a great job, and my app wouldn't be anywhere near as cool as it is without you peeps doing what you do!
< < HydraIRC > > www.Hydras-World.com
|
|
|
|
|
If you use the CTabbedMDICommandBarCtrl a bug occurs when compiling with _WIN32_IE >= 0x0500 - the rebars are restored offset to the left, and each time you restart the application, they shift over some more
Edit "tabbedmdi.h", goto line 1316 and remove the "RBBIM_IDEALSIZE" flag.
e.g.
...
for(int i = 0; i < nCount; i++)
{
#if (_WIN32_IE >= 0x0500)
REBARBANDINFO rbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE };
//REBARBANDINFO rbi = { sizeof(REBARBANDINFO), RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_IDEALSIZE | RBBIM_STYLE };
::SendMessage(GetParent(), RB_GETBANDINFO, i, (LPARAM)&rbi);
if(rbi.hwndChild == m_hWnd)
...
Hope this helps, and thanks for creating such a nice looking control!
I'm using it in my application, HydraIRC, grab it from - www.Hydras-World.com
|
|
|
|
|
Interesting. Thanks for the tip! That part of CTabbedMDICommandBarCtrl is a direct copy and paste from CMDICommandBarCtrlImpl::OnAllHookMessages. So, I take it that the default CMDICommandBarCtrl does the same thing to you in a plain vanilla WTL MDI app?
-Daniel
|
|
|
|
|
Well i know that my app does it, and someone else spotted a similar thing in the wtl docking windows stuff and posted a message there too..
It's weird, because for me, it was fine for ages, then all of a sudden starting doing it, then for another user, it did it straight away...
|
|
|
|
|
When you create a new MDI Child window it's always maximized. It should create the window in the same state as the current MDI window.
e.g.
if the current window is restored, new window created as restored.
if current window is maximized, create new window as maximized.
The default should be to always maximize MDI windows, but there should be a way to override this behaviour as it's most annoying for my app..
|
|
|
|
|
Hydra wrote:
When you create a new MDI Child window it's always maximized. It should create the window in the same state as the current MDI window.
You must be referring to the "DockingDemo" sample. If you run the 2 other MDI samples, you'll see that it does indeed do exactly what you would like. In fact, I go to extra lengths that an out-of-the-box WTL app doesn't go through to match the maximization of that last previously active MDI child.
You can see another codeproject article I wrote about this very topic:
http://www.codeproject.com/wtl/wtlmdichildmax.asp
In the "DockingDemo" sample, I am demonstrating how (via my CTabbedMDIChildWindowImpl) you can easily have your app always create MDI children as maximized - by simply including the "WS_MAXIMIZE" style for the child frame. To see the demo without this behavior, simply go to the DockingDemo's version of "HtmlFrame.h", and remove "WS_MAXIMIZE" from CHtmlFrameWinTraits
-Daniel
|
|
|
|
|
ahh, i missed that.. ok thanks! just what i wanted then
|
|
|
|
|
I'm using Windows XP, WTL 7.0, and Visual Studio .NET, when I try any of the demos, or when i use the TabbedMDI control in my app the application does not exit properly if an MDI window is still open.
Instead executing code after the line..:
int nRet = theLoop.Run();
.. it just goes "ding" and then drops back to the dev environment. No assertions, no nothing. I stepped through the code after it processes my CMainFrame::OnClose() and it exits while processing this bit of code from user32.dll
77D458A1 call dword ptr [eax+14h]
77D458A4 push 0
77D458A6 push 0Ch
77D458A8 pop edx
77D458A9 lea ecx,[ebp-0Ch]
77D458AC mov dword ptr [ebp-0Ch],eax
77D458AF call 77D444A7 <<< Exits here!
The callstack from my app is:
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::DefWindowProcA(unsigned int uMsg=0x00000010, unsigned int wParam=0x00000000, long lParam=0x00000000) Line 1270 + 0x22 C++
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::MDIFrameWindowProc(HWND__ * hWnd=0x010c7100, unsigned int uMsg=0x00000010, unsigned int wParam=0x00000000, long lParam=0x00000000) Line 1224 + 0x14 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::DefWindowProcA(unsigned int uMsg=0x00000010, unsigned int wParam=0x00000000, long lParam=0x00000000) Line 3779 + 0x21 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::WindowProc(HWND__ * hWnd=0x010c7340, unsigned int uMsg=0x00000010, unsigned int wParam=0x00000000, long lParam=0x00000000) Line 3822 + 0x14 C++
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::DefWindowProcA(unsigned int uMsg=0x00000112, unsigned int wParam=0x0000f060, long lParam=0x006d03c6) Line 1270 + 0x22 C++
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::MDIFrameWindowProc(HWND__ * hWnd=0x010c7100, unsigned int uMsg=0x00000112, unsigned int wParam=0x0000f060, long lParam=0x006d03c6) Line 1224 + 0x14 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::DefWindowProcA(unsigned int uMsg=0x00000112, unsigned int wParam=0x0000f060, long lParam=0x006d03c6) Line 3779 + 0x21 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::WindowProc(HWND__ * hWnd=0x010c7340, unsigned int uMsg=0x00000112, unsigned int wParam=0x0000f060, long lParam=0x006d03c6) Line 3822 + 0x14 C++
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::DefWindowProcA(unsigned int uMsg=0x000000a1, unsigned int wParam=0x00000014, long lParam=0x006d03c6) Line 1270 + 0x22 C++
HydraIRC.exe!WTL::CMDIFrameWindowImpl<cmainframe,wtl::cmdiwindow,dockwins::cdockingframetraitst<csimplesplitterbar<5>,114229248,262400> >::MDIFrameWindowProc(HWND__ * hWnd=0x010c7100, unsigned int uMsg=0x000000a1, unsigned int wParam=0x00000014, long lParam=0x006d03c6) Line 1224 + 0x14 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::DefWindowProcA(unsigned int uMsg=0x000000a1, unsigned int wParam=0x00000014, long lParam=0x006d03c6) Line 3779 + 0x21 C++
HydraIRC.exe!ATL::CContainedWindowT<atl::cwindow,atl::cwintraits<1442840576,0> >::WindowProc(HWND__ * hWnd=0x010c7340, unsigned int uMsg=0x000000a1, unsigned int wParam=0x00000014, long lParam=0x006d03c6) Line 3822 + 0x14 C++
HydraIRC.exe!Run(char * __formal=0x00151f18, int nCmdShow=0x00000001) Line 533 + 0x8 C++
HydraIRC.exe!WinMain(HINSTANCE__ * hInstance=0x00400000, HINSTANCE__ * __formal=0x00000000, char * lpstrCmdLine=0x00151f18, int nCmdShow=0x00000001) Line 603 + 0xd C++
HydraIRC.exe!WinMainCRTStartup() Line 251 + 0x32 C
kernel32.dll!77e7eb69()
Hope you can fix it!
|
|
|
|
|
Hydra wrote:
when I try any of the demos, or when i use the TabbedMDI control in my app the application does not exit properly if an MDI window is still open
Thanks for reporting this! I'm still looking into this, and I'll reply back to this message when I figure out what the problem is or how to fix it (hopefully both ).
Thanks,
-Daniel
|
|
|
|
|
sure thing, and if you need any more info from me, don't hesitate to ask.
|
|
|
|
|
Ok, so I thought, bugger the MDI tabs, don't really need them anyway because I have a taskbar on a rebar toolbar that controls the windows and reorders itself according to which windows you used last:
m_MyToolBar.Movebutton(currentbuttonindex, 0) //move to first button
I wish the .net ones did that, actually, add that to your TODO list too..
anyway, I digress..
So, I #ifdef'd out the MDI tabbed stuff, and implemented two docking windows, each with two tabbed views, and again, the exit problem occurs when there are MDI windows open ?!?.
So maybe the bug is not in the TabbedMDI..Impl, but instead the bug might be in the actual custom Tab Controls or maybe not, but I thought this might be useful for you to know anyway.
|
|
|
|
|
ahh, i might have narrowed it down a bit for you..
i accidentally declared my view in my base class as well as my derived class (oops!) and initilised the ones in the derived class and added them to the tabs and that's what caused exit problem in the above example.
After i removed the declaration in the derived class it all worked normally and exited without a error, even with multiple MDI windows open.
So, maybe the problem *IS* with just the MDI tabs, as I originally thought, but maybe the solution has something to do with something similar...
here's what i had:
class TextQueueManager
{
public:
CSimpleArray<textqueueitem *=""> m_TextQueue;
int m_QueueType;
CTextQueueView *m_pTextQueueView; // <-- the tabbed view...
TextQueueManager( void );
~TextQueueManager( void );
void AddItem(char *From, char *Message, char *ServerName);
void RemoveOldItems( void );
private:
void RemoveItem( TextQueueItem *pTQI );
};
class PrivMsgQueueManager :
public TextQueueManager
{
public:
//CTextQueueView *m_pTextQueueView; // <-- oops! had it here too..
PrivMsgQueueManager( void )
{
m_QueueType = CWQUEUE_PRIVMSG;
m_pTextQueueView = new CTextQueueView(this);
}
~PrivMsgQueueManager( void )
{
delete m_pTextQueueView;
}
};
|
|
|
|
|
Hydra wrote:
when I try any of the demos, or when i use the TabbedMDI control in my app the application does not exit properly if an MDI window is still open
Sorry for taking so long to get back about this.
The fix turns out to be very simple. In DotNetTabCtrl.h, replace line 719:
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_Close, &m_rcCloseButton);
with
if(m_tooltip.IsWindow())
{
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_Close, &m_rcCloseButton);
}
and line 773 and 774:
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_ScrollRight, &m_rcScrollRight);
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_ScrollLeft, &m_rcScrollLeft);
with
if(m_tooltip.IsWindow())
{
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_ScrollRight, &m_rcScrollRight);
m_tooltip.SetToolRect(m_hWnd, ectcToolTip_ScrollLeft, &m_rcScrollLeft);
}
These changes will be in my next updates.
The problem was that when all the items are deleted in DeleteAllItems (called while handling WM_DESTROY) DeleteItem is called, which calls UpdateLayout, which, when CTCS_CLOSEBUTTON and/or CTCS_SCROLL are set, tries to update their respective tooltips, but the tooltips have already been destroyed.
I'm also going to make a change to DeleteAllItems that you can make now if you like. Replace CustomTabCtrl.h line 2338:
while( GetItemCount()>0 ) DeleteItem(0U, false, true);
with
this->SendMessage(WM_SETREDRAW, FALSE, 0);
while( GetItemCount()>0 ) DeleteItem(0U, false, true);
this->SendMessage(WM_SETREDRAW, TRUE, 0);
-Daniel
|
|
|
|
|
I can't find the file "altapp.h".
|
|
|
|
|