• Advertisement


This topic is now archived and is closed to further replies.

Tab Controls in Win32

This topic is 5223 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I would like to add a tab strip to the program I''m working on. But everything I find is in MFC. I want to do it the hard way and reinvent the wheel. Is there any kind of tutorials on tab strips for Win32?

Share this post

Link to post
Share on other sites
I just recently had the same problem. I needed to find information on tab controls without mfc, and as you've probably discovered, there's not much out there. I managed to navigate through msdn to a section that was ACTUALLY helpful to me. I hope it's useful to you too.


BTW, if you navigate on the bar on the left, you can find all sorts of information on all the controls.

Good luck.

Build a man a fire and you'll keep him warm for a night.
Set a man on fire and you'll keep him warm for the rest of his life.

[edited by - pi_equals_3 on November 29, 2003 11:01:50 AM]

Share this post

Link to post
Share on other sites
I''m probably not doing this right but I keep getting an error. I copied the four functions from MSDN into a seperate file. For the couple that want the handle to the app I used GetModuleHandle(NULL) instead of using a global. It compiles fine expect for a few warnings about ''type cast''. In the WM_INITDIALOG of my main dialog I call OnTabbedDialogInit(hDlg) and it crashes at

if (pHdr->apRes->cx > rcTab.right)
rcTab.right = pHdr->apRes[i]->cx;

I''ve only got one tab but I modified the code for that. I''m not quite sure what I''m doing wrong on this.

Share this post

Link to post
Share on other sites
I pretty much just copied the code straight from MSDN.

#define C_PAGES 1

typedef struct tag_dlghdr {
HWND hwndTab; // tab control

HWND hwndDisplay; // current child dialog box

RECT rcDisplay; // display rectangle for the tab control


VOID WINAPI OnTabbedDialogInit(HWND hwndDlg);
VOID WINAPI OnSelChanged(HWND hwndDlg);
VOID WINAPI OnChildDialogInit(HWND hwndDlg);

VOID WINAPI OnTabbedDialogInit(HWND hwndDlg)
DLGHDR *pHdr = (DLGHDR *) LocalAlloc(LPTR, sizeof(DLGHDR));
DWORD dwDlgBase = GetDialogBaseUnits();
int cxMargin = LOWORD(dwDlgBase) / 4;
int cyMargin = HIWORD(dwDlgBase) / 8;
RECT rcTab;
HWND hwndButton;
RECT rcButton;
int i;
HINSTANCE g_hinst;

g_hinst = GetModuleHandle(NULL);

// Save a pointer to the DLGHDR structure.

SetWindowLong(hwndDlg, GWL_USERDATA, (LONG) pHdr);

// Create the tab control.

pHdr->hwndTab = CreateWindow(
0, 0, 100, 100,
hwndDlg, NULL, g_hinst, NULL
if (pHdr->hwndTab == NULL) {
// handle error


// Add a tab for each of the three child dialog boxes.

tie.mask = TCIF_TEXT | TCIF_IMAGE;
tie.iImage = -1;
tie.pszText = "
TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);
tie.pszText = "
TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);
tie.pszText = "
TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);

// Lock the resources for the three child dialog boxes.

pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE("
// pHdr->apRes[1] = DoLockDlgRes(MAKEINTRESOURCE(DLG_SECOND));

//pHdr->apRes[2] = DoLockDlgRes(MAKEINTRESOURCE(DLG_THIRD));

// Determine the bounding rectangle for all child dialog boxes.

for (i = 0; i < C_PAGES; i++) {
if (pHdr->apRes[i]->cx > rcTab.right)
rcTab.right = pHdr->apRes[i]->cx;
if (pHdr->apRes[i]->cy > rcTab.bottom)
rcTab.bottom = pHdr->apRes[i]->cy;
rcTab.right = rcTab.right * LOWORD(dwDlgBase) / 4;
rcTab.bottom = rcTab.bottom * HIWORD(dwDlgBase) / 8;

// Calculate how large to make the tab control, so

// the display area can accommodate all the child dialog boxes.

TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);
OffsetRect(&rcTab, cxMargin - rcTab.left,
cyMargin - rcTab.top);

// Calculate the display rectangle.

CopyRect(&pHdr->rcDisplay, &rcTab);
TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);

// Set the size and position of the tab control, buttons,

// and dialog box.

SetWindowPos(pHdr->hwndTab, NULL, rcTab.left, rcTab.top,
rcTab.right - rcTab.left, rcTab.bottom - rcTab.top,

// Move the first button below the tab control.

hwndButton = GetDlgItem(hwndDlg, IDCLOSE);
SetWindowPos(hwndButton, NULL,
rcTab.left, rcTab.bottom + cyMargin, 0, 0,

// Determine the size of the button.

GetWindowRect(hwndButton, &rcButton);
rcButton.right -= rcButton.left;
rcButton.bottom -= rcButton.top;

// Move the second button to the right of the first.

hwndButton = GetDlgItem(hwndDlg, IDOK);
SetWindowPos(hwndButton, NULL,
rcTab.left + rcButton.right + cxMargin,
rcTab.bottom + cyMargin, 0, 0,

// Size the dialog box.

SetWindowPos(hwndDlg, NULL, 0, 0,
rcTab.right + cyMargin +
2 * GetSystemMetrics(SM_CXDLGFRAME),
rcTab.bottom + rcButton.bottom + 2 * cyMargin +
2 * GetSystemMetrics(SM_CYDLGFRAME) +

// Simulate selection of the first item.


// DoLockDlgRes - loads and locks a dialog box template resource.

// Returns the address of the locked resource.

// lpszResName - name of the resource

HINSTANCE g_hinst;

g_hinst = GetModuleHandle(NULL);

HRSRC hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
HGLOBAL hglb = LoadResource(g_hinst, hrsrc);
return (DLGTEMPLATE *) LockResource(hglb);

// OnSelChanged - processes the TCN_SELCHANGE notification.

// hwndDlg - handle to the parent dialog box.

VOID WINAPI OnSelChanged(HWND hwndDlg)
HINSTANCE g_hinst;

g_hinst = GetModuleHandle(NULL);

DLGHDR *pHdr = (DLGHDR *) GetWindowLong(
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);

// Destroy the current child dialog box, if any.

if (pHdr->hwndDisplay != NULL)

// Create the new child dialog box.

pHdr->hwndDisplay = CreateDialogIndirect(g_hinst,
pHdr->apRes[iSel], hwndDlg, MainDlgProc);

// OnChildDialogInit - Positions the child dialog box to fall

// within the display area of the tab control.

VOID WINAPI OnChildDialogInit(HWND hwndDlg)
HWND hwndParent = GetParent(hwndDlg);
DLGHDR *pHdr = (DLGHDR *) GetWindowLong(
hwndParent, GWL_USERDATA);
SetWindowPos(hwndDlg, HWND_TOP,
pHdr->rcDisplay.left, pHdr->rcDisplay.top,
0, 0, SWP_NOSIZE);

[edited by - darkchrono4 on November 30, 2003 1:22:00 PM]

Share this post

Link to post
Share on other sites
Original post by darkchrono4
[lots of code]

[ source ] [ /source ] tags are usually prefered, but anyway:

pHdr->apRes[0] = DoLockDlgRes(MAKEINTRESOURCE("ONE"));

MAKEINTRESOURCE() accepts a token and turns that into a string. I''m pretty sure this line might be causing problems.

Colin Jeanne | Invader''s Realm

Share this post

Link to post
Share on other sites
you use MAKEINTRESOURCE if your resource is an actual integer name. If you use strings as resource names, just type the string.

"one" //also correct

assuming 1 is one resource, and "one" is a differently named resource

[edited by - nagromo on November 30, 2003 1:50:24 PM]

Share this post

Link to post
Share on other sites
Your dialog''s name is "ONE", with the quotes even?

Then a better way to solve the problem would be to add some error handlers (particularly in the DoLockDlgRes() function) so that you can properly debug your code.

Colin Jeanne | Invader''s Realm

Share this post

Link to post
Share on other sites
Yeah I do have some questionable coding practices.

In my comments above I was trying to add the tab strip to a dialog box. Because I''m lazy and like to use the resource editor to create my controls instead of doing them manually. I tried the code to do a tab strip on just a regular window and it works. My question now is how to I get handles to the seperate tabs so that I can add controls?

Share this post

Link to post
Share on other sites

  • Advertisement