List View を Column でソートする

成績データを List View に表示して、Column(名前,数学,英語,理科)をクリックするとソートして表示します。

前田稔(Maeda Minoru)の超初心者のプログラム入門

プロジェクトの設定

  1. 新規プロジェクトで(LVSort)を作成します。
    プロジェクトの作成は List View にカラムと見出しを付ける に順じます。
  2. commctrl.h をインクルードして、#pragma comment(lib,"comctl32.lib") を記述します。
    UP,DOWN は昇順・降順を表す ID の定義です。
    hList は List View の Handle です。
    sort[4] は Column ごとの昇順・降順の区別で交互に切り替えてソートします。
    HEAD[] は ListView の見出しで、CX[] は Column(項目) の幅です。
    t_name[][] は List View に登録する名前のテーブルです。
    t_ten[][][] は「数学・英語・理科」の成績です。
        #include    <commctrl.h>
        #pragma     comment(lib,"comctl32.lib")
        #include    "resource.h"
        #define     UP      0
        #define     DOWN    1
    
        HWND        hList;
        int         sort[4];
    
        //List View Test Data
        char    HEAD[][5]= {  "名前", "数学", "英語", "理科"  };
        int     CX[]=      {  100, 60, 60, 60  };
        char    t_name[][13]=
        {  "愛知  雅夫", "大阪  恵",   "岡山  英子", "沖縄  妙子", "京都  智史", "滋賀  佳奈子",
           "東京  慎吾", "奈良  憲彦", "兵庫  久美", "北海道  静", "三重  健一", "和歌山  絢子",
        };
        char    t_ten[][3][4]=
        {  " 0"," 0"," 0", "90","90","90", " 8","80","80", "70"," 7","70", "60"," 6","60", "50","50","50",
           "10","20","95", "30"," 9","40", "95"," 5","60", "92","98","84", "35","56","78", "78"," 6","82",
        };
        
  3. WinMain() では DialogBox を表示するだけです。
    WM_INITDIALOG: の記述です。
    ListView のハンドルを格納して SetInitialData() を呼びます。
        case WM_INITDIALOG:
            SetWindowText(hDlg,TITLE);
            InitCommonControls();
            hList= GetDlgItem(hDlg,IDC_LIST1);
            SetInitialData(hList,12);
            break;
        
  4. List View の Column をクリックすると、親ウインドウに WM_NOTIFY: として知らされます。
    List View からのメッセージのとき、sort[4] を調べて昇順と降順を交互に切り替えます。
    ListView_SortItems() 関数で指定した MyCompProc がソートの順序を判定する CALLBACK 関数の名前です。
        LV_DISPINFO     *lvinfo;
        NM_LISTVIEW     *pNMLV;
    
        case WM_NOTIFY:
            if (LOWORD(wp)!=IDC_LIST1)  break;
            lvinfo = (LV_DISPINFO *)lp;
            switch(lvinfo->hdr.code)
            {   case LVN_COLUMNCLICK:
                    pNMLV = (NM_LISTVIEW *)lp;
                    if (sort[pNMLV->iSubItem] == UP)    sort[pNMLV->iSubItem] = DOWN;
                    else                                sort[pNMLV->iSubItem] = UP;
                    ListView_SortItems(hList,MyCompProc,pNMLV->iSubItem);
                    break;
            }
            break;
        
  5. 成績データを List View に登録する関数です。
    sort[4] を昇順で初期化しています。
    Item の登録(ListView_InsertItem) は LVIF_TEXT | LVIF_PARAM を指定して下さい。
    LVIF_PARAM は item.lParam を使う指定で、lParam には項目の番号(i)を格納して下さい。
    SubItem の登録(ListView_SetItem) には LVIF_TEXT だけを指定して下さい。
        void    SetInitialData(HWND hTree, int cnt)
        {   LV_COLUMN   lvcol;
            LV_ITEM     item;
            int         i,j;
    
            for(i=0; i<4; i++)  sort[i]= UP;
            // Column の項目設定
            lvcol.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
            lvcol.fmt = LVCFMT_LEFT;
            for(i=0; i<4; i++)
            {   lvcol.cx = CX[i];
                lvcol.pszText = HEAD[i];
                lvcol.iSubItem = i;
                ListView_InsertColumn(hTree,i,&lvcol);
            }
    
            // ITEM の設定
            for(i=0; i<cnt; i++)
            {   item.mask = LVIF_TEXT | LVIF_PARAM;
                item.pszText = t_name[i];
                item.iItem = i;
                item.iSubItem = 0;
                item.lParam = i;
                ListView_InsertItem(hTree,&item);
    
                for(j=0; j<3; j++)
                {    item.mask = LVIF_TEXT;
                     item.pszText = t_ten[i][j];
                     item.iItem = i;
                     item.iSubItem = j+1;
                     ListView_SetItem(hTree,&item);
                }
            }
        }
        
  6. ソートの順序を判定する CALLBACK 関数です。
    lp1 の Item と lp2 の Item を比較して、入れ替えるか否かをリターンします。
    lp3 がソートする Column 番号です。
    buf1 と buf2 に比較する TEXT を取得して strcmp() で比較結果を返します。
        int CALLBACK MyCompProc(LPARAM lp1, LPARAM lp2, LPARAM lp3)
        {
            static LV_FINDINFO lvf;
            static int         nItem1, nItem2;
            static char        buf1[30], buf2[30];
    
            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, sizeof(buf1));
            ListView_GetItemText(hList, nItem2, (int)lp3, buf2, sizeof(buf2));
            if (sort[(int)lp3] == UP)   return(strcmp(buf1, buf2));
            else                        return(strcmp(buf1, buf2) * -1);
        }
        
  7. List View に合計点を追加して、成績順にソートしてみて下さい。
    合計点は桁数を揃えて、右詰で格納します。
    表示桁を揃えるときは DialogBox のプロパティから Font(Size) を「FixedSys」に設定して下さい。
    C# でも同様のプログラムを作成しています。
    ListView Sort を参照して下さい。

超初心者の方のために全ソースコードを掲載します。 (^_^;)
全ソースコード

超初心者のプログラム入門(Win32API C++)