C / C++ Win32 Tab control example [*UPDATED*]
I will be the first to admit that I am NOT even close to having much of a grasp of C/C++ and Win32, but I wanted to share a Tab control example with the world.
When I was trying to understand how tab controls worked in Win32, I scoured the web, and found very little in the way of decent examples. The MSDN examples I found didn’t work, so that made things even harder. So here, for your coding pleasure, is a very simple tab control example.
Forgive me if I have bad coding practices or I’m doing stuff wrong. Just let me know (but try not to toast me to a crisp in doing so).
About the example
I created this example using Code::Blocks, and tried to keep it as simple as possible. I haven’t tried it yet on VC++, so your mileage may vary.
NOTE: In order for this example to work, you will need to tell your linker about the ‘common controls’ library, libcomctl32.a for MinGW, ComCtl32.Lib for VC++, etc. It will fail if you don’t. Also, I only have Windows XP and Vista, and I know it works on those, but it may not work as intended on older versions (let us know, k?).
Here is everything all zipped up: win32-tab-control-example.zip
UPDATE: Here is the Visual C++ 2008 version. Please let me know if you encounter any problems.
Enjoy!
Code:
#define _WIN32_IE 0x0500
#include <windows.h>
/*
*******************************************************
DON'T FORGET to include the common control library
in your programming environment, or this example
will fail. On MinGW, the library is called:
libcomctl32.a in the 'lib' folder. In VC++ 2005 it's:
ComCtl32.Lib
*******************************************************
*/
#include <commctrl.h>
/* global variables */
HWND hMainWindow; // main window
HWND hTab; // our tab control
HWND hTabView1; // view window for tab1
HWND hTabView2; // view window for tab2
HINSTANCE hiInst;
/* declare procedures */
LRESULT DoTheming ();
LRESULT SetUpControls ();
LRESULT CreateTabControl ();
LRESULT CreateViewWin1 ();
LRESULT CreateViewWin2 ();
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "TabExampleApp";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
hiInst = hThisInstance;
/* enable common controls */
DoTheming();
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = GetSysColorBrush(COLOR_BTNFACE);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hMainWindow = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Win32 Tab Control Example", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
800, /* The programs width */
600, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* create all of our example controls */
SetUpControls();
/* Make the window visible on the screen */
ShowWindow (hMainWindow, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* do theming / common controls */
LRESULT DoTheming()
{
INITCOMMONCONTROLSEX icce;
icce.dwSize = sizeof ( INITCOMMONCONTROLSEX );
icce.dwICC = ICC_WIN95_CLASSES;
InitCommonControlsEx (&icce );
return 0;
}
/* set up controls */
LRESULT SetUpControls ()
{
/* once our main window is created,
create the tab and view windows */
CreateTabControl();
CreateViewWin1();
CreateViewWin2();
return 0;
}
/* create our tab control */
LRESULT CreateTabControl()
{
/* create tab control */
hTab = CreateWindowEx(
0, // extended style
WC_TABCONTROL, // tab control constant
"", // text/caption
WS_CHILD | WS_VISIBLE, // is a child control, and visible
5, // X position - device units from left
5, // Y position - device units from top
785, // Width - in device units
555, // Height - in device units
hMainWindow, // parent window
NULL, // no menu
hiInst, // instance
NULL // no extra junk
);
if (hTab == NULL)
{
/* tab creation failed -
Are the correct #defines in your header?
Have you included the common control library? */
MessageBox(NULL, "Tab creation failed", "Tab Example", MB_OK | MB_ICONERROR);
return 0;
}
/* start adding items to our tab control */
TCITEM tie; // tab item structure
/* set up our item structure */
tie.mask = TCIF_TEXT; // we're only displaying text in the tabs
/* set up Tab1 item */
tie.pszText = "Tab1"; // the tab's text/caption
if (TabCtrl_InsertItem(hTab, 0, &tie) == -1)
{
/* couldn't insert tab item */
DestroyWindow(hTab);
MessageBox(NULL, "Couldn't add Tab1", "Tab Example", MB_OK | MB_ICONERROR);
return 0;
}
/* set up Tab2 item */
tie.pszText = "Tab2"; // the tab's text/caption
if (TabCtrl_InsertItem(hTab, 1, &tie) == -1)
{
/* couldn't insert tab item */
DestroyWindow(hTab);
MessageBox(NULL, "Couldn't add Tab2", "Tab Example", MB_OK | MB_ICONERROR);
return 0;
}
return 0;
}
/* create a Static control for our View 1 */
LRESULT CreateViewWin1 ()
{
/* rect structure to hold
the tab size info */
RECT tr;
/* get the tab size info so
we can place the view window
in the right place */
TabCtrl_GetItemRect(hTab, 0, &tr);
/* create a Static control for our view window */
hTabView1 = CreateWindowEx(
0,
"STATIC",
"View 1",
WS_CHILD | WS_VISIBLE | WS_BORDER | SS_CENTER,
325,
(tr.bottom - tr.top) + 230,
150,
20,
hTab,
NULL,
hiInst,
NULL
);
return 0;
}
/* create a Static control for our View 2 */
/*
the WS_VISIBLE constant not used intentionally
and the control is slightly out of position with
the first Static control so the tab-switching
result is clearer
*/
LRESULT CreateViewWin2 ()
{
/* rect structure to hold
the tab size info */
RECT tr;
/* get the tab size info so
we can place the view window
in the right place */
TabCtrl_GetItemRect(hTab, 0, &tr);
/* create a Static control for our view window */
hTabView2 = CreateWindowEx(
0,
"STATIC",
"View 2",
WS_CHILD | WS_BORDER | SS_CENTER,
300,
(tr.bottom - tr.top) + 205,
150,
20,
hTab,
NULL,
hiInst,
NULL
);
return 0;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
/* handle the messages */
switch (message)
{
/* tab message is in WM_NOTIFY message */
case WM_NOTIFY:
/* get the tab message from lParam */
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
/* if the tab message is TCN_SELCHANGE we'll
examine it and take the appropriate action */
if (lpnmhdr->code == TCN_SELCHANGE)
{
/* get the currently selected tab item */
int iPage = TabCtrl_GetCurSel(hTab);
/* hide/show the appropriate windows based
on which tab the user clicks */
switch (iPage)
{
/* tab 1 (item 0) clicked */
case 0:
ShowWindow(hTabView2, SW_HIDE); // first hide View 2
ShowWindow(hTabView1, SW_SHOW); // then show View 1
return 0;
/* tab 2 (item 1) clicked */
case 1:
ShowWindow(hTabView1, SW_HIDE); // first hide View 1
ShowWindow(hTabView2, SW_SHOW); // then show View 2
return 0;
default:
break;
}
}
return 0;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
Hi Will!
Thank you a lot for this tab example! Very straightforward to look and learn!
But there is a little problem imho: with Pelles C it does not want to compile
with error on line 276
LPNMHDR lpnmhdr = (LPNMHDR)lParam;
If you comment this line out
and then replace the line
if (lpnmhdr->code == TCN_SELCHANGE)
like
if (((LPNMHDR)lParam)->code == TCN_SELCHANGE)
then it works. I took it from MSDN.
May it’s very silly, but me is just beginner
Thanks Will,
Appreciate the information, I’m new to Win32 programming and this laid it out nice and clearly.
Tabulicious
Hi,
The example is vey helpful.. I have small doubt.. How to set background color and text color for the tab control?
Thanks
Thanks a lot. I’ve been trying to work through the tutorial at this site…
http://www.functionx.com/win32/Lesson03.htm
It is set up for Visual C++.
The first line “#define _WIN32_IE 0×0500″ was very useful here since it must be automatically defined somewhere by the Visual C++ IDE.
Your application looks a little nicer since the control initialisation routines have been separated from the WinMain function.
wow a tab example. Why are these so sparse?
Thanks
I found here exactly I needed.
HI Will,
I am Olivier from France, and I thank you for your great job on the tab control programming in Win32,
I have been searching for days , and I found your marvellous article on it, and now I can do it.
You know, I think you are a great programmer and I read about your personal problems in life ,
We could become friend programmer.
I work on C programs in my job, I have already travelled in your country in 1991.
It was a funny and mad trip from New York, LA,SF,Arizona,New Orleans.
God, what a wonderful country !!!.
I hope I will get news from you !!!
God bless you !!!
Olivier, and everyone else who has commented so far, thank you so much!
I posted this tab example to help people. I know it was difficult for me to find any good Win32 tab examples on the web, so I didn’t want other people to have the same problem. Hopefully, when time allows, I can put other examples up.
Thank you again, and God bless you all!
Hi ,I am happy to get your answer,
Thanks God,since we are friends now, I send you the address of the song of a french singer
who unfortunately died a few days ago, the whole France is crying for this singer
you put this address in http://www.youtube.com
http://www.youtube.com/watch?v=NiOHAlkNZa8
this guy is Alain Bashung
i hope you will enjoy it.
Here come a huge THANK YOU from me. Ive been searching the net for an example of tabs in c++ the whole day, was about to give up when I hit this page. It is awesome and easy to understand, keep up the good work!
Andreas, you are very welcome. I am not an expert, but I do I enjoy sharing whatever knowledge I do have.