Creating a Tab Control

You create a tab control by calling the CreateWindow or CreateWindowEx function and specifying the WC_TABCONTROL window class. This window class is registered when the dynamic-link library for Win32 common controls (COMCTL32.DLL) is loaded. You also need to link with the COMCTL32.LIB library.

To include tabs in a window, the application must also fill out the TC_ITEM or TC_ITEMHEADER structure. These two structures specify the attributes of the tabs. TC_ITEM and TC_ITEMHEADER are nearly identical, except that TC_ITEMHEADER lets you specify extra application-specific data. To do this, the application should define its own structure, consisting of the TC_ITEMHEADER structure followed by application-defined data, and then set the total number of bytes per tab using the TCM_SETITEMEXTRA message. For example, if my application stored information about a baseball player for each tab, I would define a structure that looks something like the code on the following page.

typedef struct _PLAYER_TAB 
{
TC_ITEMHEADER tci; // tab item information
LPSTR lpstrName; // player's name
LPSTR lpstrTeam; // player's team
LONG lERA; // player's ERA
LONG lSalary; // player's salary
BOOL bCap; // salary cap?
} PLAYER_TAB;

After adding the tabs to the tab control, the application sends the TCM_SETITEMEXTRA message to set the amount of data to sizeof (PLAYER_TAB). If the application needs to store a pointer to the structure without including TC_ITEMHEADER in the structure, it can instead use TC_ITEM and store the pointer to the structure in the lParam field.

Let's look at some simple code that fills out the TC_ITEM structure and creates a tab within a tab control by calling the TabCtrl_InsertItem macro. The following code snippet creates a tab control that contains text and has no image list associated with it:

TC_ITEM tie;

tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = "Tab 1";

if (TabCtrl_InsertItem (hwndTab, i, &tie) == -1)
{
// The insert failed; display an error box.
MessageBox (NULL, "TabCtrl_InsertItem failed!", NULL, MB_OK);
return NULL;
}

So far, you've created a tab control and inserted tab items, but the tab control still doesn't have much functionality. The application must now manage the window associated with the tabs. You can do this the easy way or the not-so-easy way. The easy way is to use a property sheet in conjunction with tabs, as described later in this chapter.

The not-so-easy way is to handle the TCN_SELCHANGE notification that is sent through a WM_COMMAND message. This notification is sent when the user clicks a tab and the application needs to switch pages. The application processes the notification and makes the appropriate changes to the focus window. With this method, you could, for example, allow the application to use one edit control for all the tabs. The application would assign the memory handle (send an EM_SETHANDLE message to the edit control) for the incoming page. Although this method certainly works, a better way to handle paging between tabs is to let the system do the grunt work for you and to use a property sheet instead.