#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はマクロ関数で、内部的にはウインドウにメッセージを投げてるのね。そんなオーバーヘッドでかいことする必要あるのか?とか思うんだけど、そういうもんなのかね。
ま、とりあえずやりたいことは全部できた。後は組み合わせるだけですね。ソート可能なリストビューにアクティブなプロセスの時間を載せれば完成かな?