As others have mentioned, ListBox controls don't allow for multiple columns of data for each item. A ListBox is scrollable in one direction or the other, while a ListView is scrollable in both directions.
Windows explorer uses a ListView - right-click inside the client area of the window and you can change the view to Details - this gives a heading control and several columns per file - size, date, name etc, etc.
In any case, no - sorting won't work automatically when you click on the column header.
You'll get a notification of LVN_COLUMNCLICK via the WM_NOTIFY message. It's then up to you to determine which column was clicked on and whether you want to sort in ascending or descending order.
Having done so, you would then call ListView_SortItems with a pointer to the appropriate sorting function, the HWND of the control and an application-defined lParam value.
There are a couple of ways to go about it - typical uses the lParam value may be to flag whether the sorting is in ascending or descending order. You could also get clever, and use negative values for sorting in one direction and positive numbers for sorting in the other direction. Abs(lParam) could be used to hold the column index that you wish to perform the sort on.
Another approach may be to have one sorting function per column, calling ListView_SortItems using the appropriate function each time.
Ensuring that you give each ListView item a lParam value when adding them, gives you an identifier that can be used to extract the text from any column, which is then used for sorting.
Perhaps you'd like to look over the following code:
#include <pre><windows.h>
#include <stdio.h>
#include <commctrl.h>
#define IDC_ListView1 10001
enum gender {male=0, female};
typedef struct person_t
{
char *firstName;
char *lastName;
int age;
gender sex;
};
person_t peopleList[] =
{
{"Micky", "Mouse", 61, male},
{"Donald", "Duck", 59, male},
{"Betty", "Boo", 34, female},
{"Olive", "Oil", 32, female},
{"Clark", "Kent", 29, male}
};
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
char szClassName[ ] = "CodeBlocksWindowsApp";
BOOL insertListViewColumn(HWND listHwnd, char *columnText, int colIndex)
{
CHAR szText[256];
LVCOLUMN lvc;
int iCol;
lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
iCol = colIndex;
lvc.iSubItem = iCol;
lvc.pszText = columnText;
lvc.cx = 70;
lvc.fmt = LVCFMT_LEFT;
if (ListView_InsertColumn(listHwnd, iCol, &lvc) == -1)
return FALSE;
return TRUE;
}
void addListViewItem(HWND hWndListView, char *pszText, int iItem, int iSubItem, int iImage=-1)
{
LVITEM lvItem;
ZeroMemory(&lvItem, sizeof(LVITEM));
lvItem.mask = LVIF_TEXT;
lvItem.iItem = iItem;
lvItem.iSubItem = iSubItem;
lvItem.pszText = pszText;
lvItem.cchTextMax = strlen(pszText);
if (iImage != -1)
{
lvItem.mask |= LVIF_IMAGE;
lvItem.iImage = iImage;
}
if (iSubItem == 0)
{
if (ListView_InsertItem(hWndListView, &lvItem) == -1)
return;
}
else
{
if (ListView_SetItem(hWndListView, &lvItem) == -1)
return;
}
}
BOOL InsertPersonIntoListView(HWND hWndListView, person_t person)
{
static int curItemIndex = 0;
char szBuffer[256];
addListViewItem(hWndListView, person.firstName, curItemIndex, 0, -1);
addListViewItem(hWndListView, person.lastName, curItemIndex, 1, -1);
sprintf(szBuffer,"%d", person.age);
addListViewItem(hWndListView, szBuffer, curItemIndex, 2, -1);
sprintf(szBuffer,"%s", person.sex==male?"male":"female");
addListViewItem(hWndListView, szBuffer, curItemIndex, 3, -1);
curItemIndex++;
}
int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszArgument, int nCmdShow)
{
HWND hwnd;
MSG messages;
WNDCLASSEX wincl;
wincl.hInstance = hInst;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure;
wincl.style = CS_DBLCLKS;
wincl.cbSize = sizeof (WNDCLASSEX);
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL;
wincl.cbClsExtra = 0;
wincl.cbWndExtra = 0;
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
if (!RegisterClassEx (&wincl))
return 0;
hwnd = CreateWindowEx(0, szClassName, "ListView Sorting demo", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 426, 154,
HWND_DESKTOP, NULL, hInst, NULL);
HWND btnWnd, listViewWnd;
InitCommonControls();
listViewWnd = CreateWindow(WC_LISTVIEW, "", WS_CHILD|WS_VISIBLE|LVS_REPORT, 5,5, 400,100, hwnd, (HMENU)IDC_ListView1, hInst, 0);
insertListViewColumn(listViewWnd, "First Name", 0);
insertListViewColumn(listViewWnd, "Last Name", 1);
insertListViewColumn(listViewWnd, "Age", 2);
insertListViewColumn(listViewWnd, "Sex", 3);
for (int i=0; i<sizeof(peopleList)/sizeof(peopleList[0]); i++)
InsertPersonIntoListView(listViewWnd, peopleList[i]);
ShowWindow (hwnd, nCmdShow);
while (GetMessage (&messages, NULL, 0, 0))
{
TranslateMessage(&messages);
DispatchMessage(&messages);
}
return messages.wParam;
}
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int idControl;
char szText[256];
NM_LISTVIEW *pnmv;
switch (message)
{
case WM_DESTROY:
PostQuitMessage (0);
break;
case WM_NOTIFY:
idControl = (int)wParam;
if (idControl == IDC_ListView1)
{
pnmv = (NM_LISTVIEW*) lParam;
if (pnmv->hdr.code == LVN_COLUMNCLICK)
{
sprintf(szText, "Column %d clicked", pnmv->iSubItem);
MessageBox(hwnd, szText, "ListView WM_NOTIFY message", MB_OK);
}
}
break;
default:
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
|