Archived

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

Tab Controls in Win32

This topic is 5128 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.

Clicky

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

DLGTEMPLATE *apRes[C_PAGES];
} DLGHDR;

VOID WINAPI OnTabbedDialogInit(HWND hwndDlg);
DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName);
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;
TCITEM tie;
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.

InitCommonControls();
pHdr->hwndTab = CreateWindow(
WC_TABCONTROL, "",
WS_CHILD | WS_CLIPSIBLINGS | WS_VISIBLE,
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 = "
First";
TabCtrl_InsertItem(pHdr->hwndTab, 0, &tie);
tie.pszText = "
Second";
TabCtrl_InsertItem(pHdr->hwndTab, 1, &tie);
tie.pszText = "
Third";
TabCtrl_InsertItem(pHdr->hwndTab, 2, &tie);

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

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

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


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

SetRectEmpty(&rcTab);
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,
SWP_NOZORDER);

// Move the first button below the tab control.

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

// 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,
SWP_NOSIZE | SWP_NOZORDER);

// 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) +
GetSystemMetrics(SM_CYCAPTION),
SWP_NOMOVE | SWP_NOZORDER);

// Simulate selection of the first item.

OnSelChanged(hwndDlg);
}

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

// Returns the address of the locked resource.

// lpszResName - name of the resource


DLGTEMPLATE * WINAPI DoLockDlgRes(LPCSTR lpszResName)
{
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(
hwndDlg, GWL_USERDATA);
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);

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

if (pHdr->hwndDisplay != NULL)
DestroyWindow(pHdr->hwndDisplay);

// 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
quote:
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.

MAKEINTRESOURCE(1) //correct
"one" //also correct
MAKEINTRESOURCE("one") //bad!

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
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
I''m using a NMHDR struct in the WM_NOTIFY message so that I know when a tab has changed. I check the .code parameter to see if a tab has actually changed. I gather from MSDN that .idFrom is the ID of the actual tab that has focus. But when I try to get this info it always comes up as a zero when I switch tabs. Is there a little more that I''m supposed to do?

Share this post


Link to post
Share on other sites
Thanks! I got it figured out.


case WM_NOTIFY:
lpnmhdr = (LPNMHDR)lParam;

if (lpnmhdr->code == TCN_SELCHANGE)
{
i = TabCtrl_GetCurSel(g_hwndTab);
/* Update display for new tab */
}

return 0;

Share this post


Link to post
Share on other sites