To create a header control specify WC_HEADER as the window class and register the class by specifying the ICC_LISTVIEW_CLASSES bit flag in the accompanying INITCOMMONCONTROLSEX structure.
Header items are inserted and managed by sending messages such as HDM_INSERTITEM, HDM_DELETEITEM, and HDM_SETITEM. By default, each section displays a text label and a separator; however, specifying the HDS_BUTTONS window style causes each header section to behave like a push button, allowing the application to respond to user clicks on the
#include <windows.h> #include <commctrl.h> #define ID_HEADER 100 #pragma comment(lib, "comctl32.lib") HWND CreateHeader(HWND hwndParent); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; MSG msg; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wc.lpszMenuName = NULL; wc.lpszClassName = TEXT("myWindowClass"); wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); RegisterClassEx(&wc); CreateWindowEx(WS_EX_CLIENTEDGE, TEXT("myWindowClass"), TEXT("Header Control"), WS_VISIBLE | WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 120, NULL, NULL, hInstance, NULL); while(GetMessage(&msg,NULL,0,0)>0) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HWND headerCtl; switch(msg) { case WM_CREATE: { INITCOMMONCONTROLSEX icex; icex.dwSize = sizeof(INITCOMMONCONTROLSEX); icex.dwICC = ICC_LISTVIEW_CLASSES; InitCommonControlsEx(&icex); headerCtl = CreateHeader(hwnd); break; } case WM_SIZE: { RECT rect; HDLAYOUT hdl; HDITEM hdi; WINDOWPOS winpos; GetClientRect(hwnd,&rect); hdl.prc = ▭ hdl.pwpos = &winpos; Header_Layout(headerCtl,&hdl); MoveWindow(headerCtl, winpos.x, winpos.y, winpos.cx, winpos.cy, TRUE); hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; hdi.pszText = TEXT("column 2"); hdi.cxy = rect.right - 150; hdi.cchTextMax = lstrlen(hdi.pszText); hdi.fmt = HDF_LEFT | HDF_STRING; SendMessage(headerCtl, HDM_SETITEM, (WPARAM)1, (LPARAM)&hdi); break; } case WM_NOTIFY: { NMHEADER *header_item; header_item = (NMHEADER *)lParam; if(header_item->hdr.code == HDN_ITEMCLICK) { switch(header_item->iItem) { case 0: MessageBox(NULL, TEXT("header 1"), TEXT("header 1 clicked"), MB_OK); break; case 1: MessageBox(NULL, TEXT("header 2"), TEXT("header 2 clicked"), MB_OK); break; } } return 0; } case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd,msg,wParam,lParam); } return 0; } HWND CreateHeader(HWND hwndParent) { HWND hwndHeader; RECT rcParent; HDLAYOUT hdl; WINDOWPOS wp; hwndHeader = CreateWindowEx(0, WC_HEADER, NULL, WS_CHILD | WS_BORDER | HDS_BUTTONS | HDS_HORZ, 0, 0, 0, 0, hwndParent, (HMENU)ID_HEADER, NULL, NULL); if(hwndHeader == NULL) return NULL; GetClientRect(hwndParent,&rcParent); hdl.prc = &rcParent; hdl.pwpos = ℘ if(!SendMessage(hwndHeader, HDM_LAYOUT, 0, (LPARAM)&hdl)) return NULL; SetWindowPos(hwndHeader, wp.hwndInsertAfter, wp.x, wp.y, wp.cx, wp.cy, wp.flags | SWP_SHOWWINDOW); HDITEM hdi; // Column 1 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; hdi.pszText = TEXT("column 1"); hdi.cxy = 150; hdi.cchTextMax = lstrlen(hdi.pszText); hdi.fmt = HDF_LEFT | HDF_STRING; SendMessage(hwndHeader, HDM_INSERTITEM, (WPARAM)0, (LPARAM)&hdi); // Column 2 hdi.mask = HDI_TEXT | HDI_FORMAT | HDI_WIDTH; hdi.pszText = TEXT("column 2"); hdi.cxy = rcParent.right - 150; hdi.cchTextMax = lstrlen(hdi.pszText); hdi.fmt = HDF_LEFT | HDF_STRING; SendMessage(hwndHeader, HDM_INSERTITEM, (WPARAM)1, (LPARAM)&hdi); return hwndHeader; }