#include <windows.h> #include <commctrl.h> #include <string.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); int CALLBACK listcmp(LPARAM lp1, LPARAM lp2, LPARAM lp3); int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int nShowCmd){ (省略) } LPTSTR key[] = {"key1", "key2", "key3"}; LPTSTR val[] = {"val1", "val2", "val3"}; int order[3] = {1,1,1}; // 0:昇順 1:降順 HWND hList; LRESULT CALLBACK WndProc (HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam) { LV_COLUMN col; LV_ITEM item; int i, subitem; switch(nMsg){ case WM_CREATE: InitCommonControls(); hList = CreateWindowEx( 0, /* 拡張ウインドウスタイル */ WC_LISTVIEW, NULL, /* クラス名 タイトル */ WS_CHILD | WS_VISIBLE | LVS_REPORT, /* ウインドウスタイル */ 0, 0, 0, 0, /* 位置、サイズ */ hWnd, /* 親ウインドウ */ (HMENU)1, /* メニューハンドル */ ((LPCREATESTRUCT)lParam)->hInstance, /* インスタンス */ NULL); /* WM_CREATE時に渡される引数 */ col.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; col.fmt = LVCFMT_LEFT; col.cx = 100; col.pszText = "key"; col.iSubItem = 0; ListView_InsertColumn(hList, 0, &col); col.cx = 200; col.pszText = "value"; col.iSubItem = 1; ListView_InsertColumn(hList, 1, &col); for(i=0; i<3; i++){ item.mask = LVIF_TEXT | LVIF_PARAM; item.pszText = key[i%3]; item.iItem = i; item.iSubItem = 0; item.lParam = i; ListView_InsertItem(hList, &item); item.mask = LVIF_TEXT; item.pszText = val[i%3]; item.iItem = i; item.iSubItem = 1; ListView_SetItem(hList, &item); } break; case WM_NOTIFY: if (((LPNMHDR)lParam)->hwndFrom == hList){ if(((LV_DISPINFO *)lParam)->hdr.code == LVN_COLUMNCLICK){ subitem = ((NM_LISTVIEW *)lParam)->iSubItem; order[subitem] = 1 - order[subitem]; ListView_SortItems(hList, listcmp, subitem); } } break; case WM_SIZE: MoveWindow(hList, 0, 0, LOWORD(lParam), HIWORD(lParam), TRUE); break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, nMsg, wParam, lParam)); } return 0; } int CALLBACK listcmp(LPARAM lp1, LPARAM lp2, LPARAM lp3) { LV_FINDINFO lvf; int nItem1, nItem2; char buf1[256], buf2[256]; lvf.flags = LVFI_PARAM; lvf.lParam = lp1; nItem1 = ListView_FindItem(hList, -1, &lvf); lvf.lParam = lp2; nItem2 = ListView_FindItem(hList, -1, &lvf); ListView_GetItemText(hList, nItem1, (int)lp3, buf1, 256); ListView_GetItemText(hList, nItem2, (int)lp3, buf2, 256); return(order[(int)lp3]==0) ? strcmp(buf1, buf2) : strcmp(buf2, buf1); }
大体一緒だけど、項目名をマウスでクリックするとWM_NOTIFY、LVN_COLUMNCLICKというイベントが渡されるのでそれをキャッチすればいいらしい。lParamのキャストされっぷりがすごいなと思うわけですが、データサイズがおなじで型名だけが違うのかなあ・・・。なんかめちゃめちゃしてるよな・・・。
アイテムを挿入するときに
item.mask = LVIF_TEXT | LVIF_PARAM;
LVIF_PARAMつけて、item.lParamにユニークなIDを入れておく。これをしないとソートされないので注意のこと。後はアイテムにLVIF_PARAMフラグをつけるけど、サブアイテムをセットするときにはフラグはつけない。つけると(なぜか)サブアイテムが表示されない状態になってしまいます。内部の実装がどうなってるのか今ひとつ分からないのですが・・・。
内容は
http://www.kumei.ne.jp/c_lang/sdk2/sdk_110.htm
ほとんどそのままなので特にこっちで言うこともないかな・・・。それにしても比較関数の不細工さは何とかならないもんか。ListView_xxxはマクロ関数で、内部的にはウインドウにメッセージを投げてるのね。そんなオーバーヘッドでかいことする必要あるのか?とか思うんだけど、そういうもんなのかね。
ま、とりあえずやりたいことは全部できた。後は組み合わせるだけですね。ソート可能なリストビューにアクティブなプロセスの時間を載せれば完成かな?