antenn-a
company profile

MFC航海日記 三十六日(CListCtrlでアイテムのソート 実装編)

今回はようやく実装編をお届けしたいと思う。 しかしまぁ、ここ2日間はすごいペースだったな。

2日で7話も書く事になるとは正直言って思わなかった。

さて、今回は CListCtrl を継承した EListCtrl 内に実装する事を前提として話を進めたい。 静的関数を用いる事やいろいろな理由により客観的に見たのでは嘘が入ってしまう(なぁぁんて言ってたらこの連載自体嘘の固まりであるが)

さて、いきなりだがコードから記述したいと思う。
char        buf[ 1024 ];
int         column = -1;
int         sort = -1;

void EListCtrl::AddItem( char* item1, char* item2, char* item3 )
{
    //最初の段階ですべてのアイテムに番号付けを行う
    static    int   i = 0;
    int             nValue;
    LV_ITEM         lvi;

    //第一カラム
    lvi.mask = LVIF_TEXT | LVIF_PARAM;
    lvi.iItem = i;
    lvi.iSubItem = 0;
    lvi.pszText = item1;
    lvi.lParam = i;

    nValue = InsertItem( &lvi );

    //第二カラム
    lvi.mask = LVIF_TEXT;
    lvi.iItem = nValue;
    lvi.iSubItem = 1;
    lvi.pszText = item2;
    SetItem( &lvi );

    //第三カラム
    lvi.mask = LVIF_TEXT;
    lvi.iItem = nValue;
    lvi.iSubItem = 2;
    lvi.pszText = item3;
    SetItem( &lvi );

    i++;
    //現在設定されているソート情報をクリア
    column = -1;
}

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    //メインダイアログの取得
    CMainDlg* d = (CMainDlg*)AfxGetMainWnd();
    ASSERT_VALID( d );

    LV_ITEM     lvi;
    CString     str1;
    CString     str2;

    lvi.mask = LVIF_TEXT;
    lvi.iSubItem = lParamSort;
    lvi.pszText = buf;
    lvi.cchTextMax = sizeof( buf );

    lvi.iItem = lParam1;
    //この関数が静的関数のため、メインフレームから情報を取得
    d->m_ListCtrl.GetItem( &lvi );
    str1 = buf;
    lvi.iItem = lParam2;
    //この関数が静的関数のため、メインフレームから情報を取得
    d->m_ListCtrl.GetItem( &lvi );
    str2 = buf;
    
    return sort ? str1 < str2 : str1 > str2;
}

void    EListCtrl::ReNumberItems()
{
    LV_ITEM     lvi;
    lvi.mask = LVIF_PARAM;
    int count = GetItemCount();

    for( int i = 0; i < count; i++ ){
        lvi.iItem = i;
        lvi.lParam = i;
        for ( int j = 0; j < 3; j++ ){
            lvi.iSubItem = j;
            //
            SetItem( &lvi );
        }
    }
}

void EListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
{
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
    int sub = pNMListView->iSubItem;

    sort = ( column == sub ? !sort : 0 );
    column = sub;

    ReNumberItems();
    SortItems( CompareFunc, sub );
    //
    
    *pResult = 0;
}

prev


というコードになった。 さて、お分かりになるでしょうか?(分かるわけねぇって?

まず、リストにアイテムを挿入した時にそのアイテム一つ一つについて番号をつけました。 後でCompareFunc()のなかでこの番号を頼りにデータを引き出します。

しかし、一回ソートしてしまうとこの番号がずれてしまう為、ソートする前には必ず ReNumberItems()を呼ぶ事にします。

この関数では上からアイテムに番号を振るだけの関数です。

prev


更に、ソートには2種類のソートがありますよね?昇順ソートと降順ソートです。 これを実現する為にグローバルの変数を用意しました。 それが、「sort」です。

詳しくはCompareFucn()を見れば分かると思います。

その他に、ソートし直しのタイミングは、
1. ほかのカラムがクリックされた
2.アイテムが追加された
の2種類があるので、カラムがクリックされた時はクリックされたカラムの番号を取っておく必要があります。 それが「column」です。(グローバルで宣言されているやつ)

初期値は -1 で、この状態だった場合は無条件に昇順ソートします。 もし、押されたカラムが前回ソートされた状態だったら降順ソートに切り替えます。

と言う事をやっているのが
    int sub = pNMListView->iSubItem;

    sort = ( column == sub ? !sort : 0 );
    column = sub;
の部分ですね。

まぁ、ここまで書けば行数は結構ありますが、たいした内容でないので大丈夫だと思います。

prev


断っておきますが、これはカラムの数が3つに限定の場合のサンプルです。 決して汎用的なサンプルではないのでご注意を!

当初汎用的な基本継承クラスを作成しようとしたのですが、非常に複雑な中身になってしまっている為難しかったのです。 従って局地的なクラスの公開になっていますが、これはよくない事ですね。

少なくともオブジェクト思考ではないな・・・(^^;;;

prev


今回のサンプルプログラムは・・・・ありません! って言うか作れなかった。

どうしようもない腐ったサンプルなら公開できますが、今の段階で公開はしないほうがよいと思いました。 どうしても欲しい方はメールください。



antenn-a

prev next


antenn-a