Introduction

Have you ever wanted to create a "tabbed window" effect, but found the amount of
information on the web lacking? Or, did you find out how to use "property sheets", but thought that method was too complicated?

Background

I was in both of those situations for years, and it seemed like I would never be able to use tabs how I wanted.
That I couldn't "get" property sheets may be a testament of my programming ability. Yet, it may have
been a more mature programmer who was able to create a different, simpler method. I submit this method in
the hope that it's usefulness outweighs any criticisms.

How It Works

Uses normal dialogs, along with some positioning and hiding.
Child windows are placed on top of a tab control in the main window.

Getting Started

There are 3 major steps to getting this to work:

Prepare the dialogs

Set up main dialog's header file

Code main dialog's methods

Prepare the Dialogs

Make a tab control on the main window. This is the style I used, but it shouldn't be important:

Create four standard blank dialogs, one for each tab, with these settings (style is important):

Check "Control parent" in "Extended Styles" if you want to be able to tab in and out from the tab control and the child windows.
Create the classes for each child dialog as you normally would in ClassWizard, and that's all you need to set up for them!
I put a simple, appropriately labeled Static Text control on each one just so I knew that it worked. You can resize the
dialogs to the planned run-time size for easier arrangement of their controls, but that will be handled programmatically
when the child window is shown.

void CSettingsDlg::OnSelchangeTab(NMHDR* pNMHDR, LRESULT* pResult)
{
// Get the number of the currently selected tab, and show its window
ShowWindowNumber(m_cTab.GetCurFocus());
// Do something with the "formal parameters" so
// the compiler is happy in warning level 4
pNMHDR = NULL;
pResult = NULL;
}

Points of Interest

I didn't realize the current code in ShowWindowNumber right away. It had a lot of
if/elseif/../else conditions with essentially the same code in each.
I would not have shared this code if I had not found a better way to switch the windows. Thus,
ShowWindowNumber is the most important and interesting part of this article.

Where Can You Go From Here?

You can use this idea to make a settings dialog in your application.

The members of each tab window can be accessed like this:

// m_dSettingsDlg is the instance of the settings dialog
// m_sString is attached to an EditBox in the General dialog
CString string = m_dSettingsDlg.m_dGeneralDlg.m_sString;

There is a lot of room for improvement if used in an actual application, but this shows the basic implementation.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

Hi,This is a very useful article and it helped me working on some applications. For one application I need to automatically switch from one tab to a different tab as soon as the user has made some input.How can I get this managed ? I have been trying to set some variables of the main dialog in a subdialog but in every case the application crashes as the handle to the window is always zero. Does anybody have experience on this ?

How can I add a propertysheet to a propertywindow of a file with particular extension(appears when we rigt click on a particular file and take the properties option)?.For eg,I want to add a new propertysheet to the propertywindow of every file with extension .bmp

Hi.U did a grt job, it is very helpfull for who learn Tab Dialogs.I have one question.I created one dialog boxe, and I created a second dialog with tab control. I called the first two dialog boxe in the second one's tab control like how u explained in project.along with this i had created a database and i created one class for this database.now what i am trying is creating 5 edit controls on first dialog box and one add button on second dialog box where we have tab control, and update database from the first dialog box.

So my question is how can I handle the controls on first dialog box from the tab dialog box.

OR

I can use database form Dialog1.And I can use database form the dialog1. Then I tried wth calling this dialog1 in tabcontrol in dialog2. So I can Use dialog1 in dialog2. But total application is getting hang when i clicked on the dialog1 embeded in dialog2 tab control.

i found this code extremely useful and have used it as a template for designing my application. However i want to know what the maximum limit is on the number of tabs i can have in one main window. VC++ 6 (the version i am using) shows 5 tabs when we create the window initially. Is this the maximum or can i add more tabs?

Any insight on how to get the dialogs on the tab sheets to resize? I have managed to get the tab control to resize when my main dialog is resized, but am having issues getting the dialogs on each tab sheet to resize as well. Has anyone ran into this?

I was sooo close to give up on the tabs.I must have tested 10 different project and all of them was crashing (mostly when applied to my own project)or missing something so when i read your article i thought yeah right easy but i gotte say FINALLY i'm able to use this TABS.

Thank you so much for this article! I'm using it to create a series of pages, each of which will have numerous checkboxes from which the user may chose. I would also like to add two buttons: "Check All" and "Clear All" to each page. However, on my first attempt, when I right-clicked on the Check All button, and went to the Class Wizard to add the event handler and code, it took me to the class constructor instead of an "OnCheckAll" function. Is there something special I have to do to add buttons to a child window?

I see a lot of hard-coded values in OnInitDialog: // Set the size and location of the child windows based on the tab control m_rSettingsRect.left = 13; m_rSettingsRect.top = 44; m_rSettingsRect.right = tabRect.Width() - 7; m_rSettingsRect.bottom = tabRect.Height() - 38;

Basically, we are making use of the tab control's built-in support for giving us its client area.

Hope this is helpful...

BTW, does this work with XP themes? In other words, do the controls like static text and check boxes paint with the almost-white background, or do they still paint with the button-face color?

It has been my experience that using tab controls doen't work well in XP. I am currently exploring using a custom CPropertySheet class that turns off all the normal buttons and removes the title and border.

Fred Koestner wrote:I see a lot of hard-coded values in OnInitDialog:// Set the size and location of the child windows based on the tab controlm_rSettingsRect.left = 13;m_rSettingsRect.top = 44;m_rSettingsRect.right = tabRect.Width() - 7;m_rSettingsRect.bottom = tabRect.Height() - 38;

Basically, we are making use of the tab control's built-in support for giving us its client area.

Hope this is helpful...

BTW, does this work with XP themes? In other words, do the controls like static text and check boxes paint with the almost-white background, or do they still paint with the button-face color?

It has been my experience that using tab controls doen't work well in XP. I am currently exploring using a custom CPropertySheet class that turns off all the normal buttons and removes the title and border.

That looks good, I'll have to try it. It seems like it would do the same thing with a better method.

XP themes? I would have to admit that property sheets and pages would be better for conforming with such a pervasive GUI. Maybe you could use owner-drawn controls along with those classes. I haven't gotten into that yet, but I've seen some cool stuff that other people have done.

Considering how many times I've seen solutions like this that DON'T handle tabbing between child controls properly, it would have been nice if you had put controls on your child dialogs.

I notice that every time you change tabs, you reposition the the visible child dialog. Not a lot of overhead, I'm sure, but hardly needed. Additionally, the control flow through that function seems backwards: if(count == number) { ShowWindow } else { HideWindow }might be more appropriate.

Considering how many times I've seen solutions like this that DON'T handle tabbing between child controls properly, it would have been nice if you had put controls on your child dialogs.

I notice that every time you change tabs, you reposition the the visible child dialog. Not a lot of overhead, I'm sure, but hardly needed. Additionally, the control flow through that function seems backwards:if(count == number){ShowWindow}else{HideWindow}might be more appropriate.

1. It actually does tab between the child controls properly, I just thought putting controls with tab stops was excessive for a simple, tutorial example. When I update this, I will consider putting some on.

Something that might be weird happens when tabbing in and out from the child windows, the tab control, and main window controls: when preparing this example (I based it on code from an application I made first), I forgot to set the tab control as the LAST tab number. Otherwise, it should work as expected.

2. The efficiency in showing and positioning the windows is certainly arguable; you have produced some good criticisms. I'll explain why I chose to do it that way.

a. I figured that each child window needing to be positioned properly before it is shown the first time is a given.

If a certain child window is shown more than once, than the method is less efficient, assuming that the main window wasn't moved (in that case the child window would have to be moved to keep the same position in the main window, and keeping track of the change would increase the overhead).

If not every child window needs to be shown, then it is more efficient to position the child windows "on demand" (they are not repositioned when hidden).

b. I thought that the most common condition should be the first condition tested, the second common the second tested, etc. Practically speaking, there are a lot more windows that are going to be hidden than shown. Even if there are only two child windows, the probability that a window needs to be shown isn't greater than 50%.

I hope that I've answered your questions. This was the first critical response-to-a-response that I've written on CP for one of my articles.