antenn-a
company profile

MFC航海日記 三十五日(CListCtrlでアイテムのソート 解説編)

先日実装しようとして止めた(失敗した)リストコントロールのソートについて今回は再挑戦してみた。 まぁ、感想としては、「止めときゃよかった」、「なんでこんなにめんどっちぃの?」といった感じである。

CListCtrl のヘルプを引いてみると、CListCtrl::SortItems()なるメンバ関数がある。 「お!MSやるじゃん!」と思って見てみると、「わ・・・わからん!!!

引用すると、
*********************************************************************
CListCtrl::SortItems
BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData );

戻り値

正常終了した場合は 0 以外を返します。それ以外の場合は 0 を返します。

引数

pfnCompare アプリケーション定義の比較関数のアドレス。
この比較関数は、ソート操作中に、2 つのリスト アイテムの相対関係を比較する
必要が生じるたびに呼び出されます。

比較関数は、クラスの静的メンバか、またはいずれのクラスのメンバでもない
スタンドアロン関数である必要があります。

dwData 比較関数に渡されるアプリケーション定義の値。

解説

アプリケーション定義の比較関数を使ってリストビュー アイテムをソートします。
各アイテムのインデックスは、新しい順序を反映して変更されます。

比較関数は次の形式をとります。

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

比較関数は、最初のアイテムが 2 番目のアイテムよりも前になると負の値を、
最初のアイテムが 2 番目のアイテムの後にくると正の値を、
2 つのアイテムが等しいときは 0 を返すようにします。

引数 lParam1 と lParam2 は、比較される 2 つのアイテム データを指定します。
引数 lParamSort は、dwData 値と同じ値です。
*********************************************************************

prev


ちょ・・・ちょっとまて!!!なんじゃコリャ!意味分からん。 これを見て一発で理解できる人はよほどの実力者か重度のMSウィルスにやられているに違いない。

私流に解読すると、
*********************************************************************
CListCtrl::SortItems (注意!あんまり役に立ちません^^)
BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData );

戻り値

正常終了した場合は 0 以外を返します。それ以外の場合は 0 を返します。
ってなってるけど、自前でやったほうがはやいかも?

引数

pfnCompare アプリケーション定義の比較関数のアドレス。
って書いたけど、要は関数名をかこうね (^^)v

この比較関数は、ソート操作中に、2 つのリスト アイテムの相対関係を比較する
必要が生じるたびに呼び出されます。
つまり、自前で比較しようと思った時に呼べってことでね

比較関数は、クラスの静的メンバか、またはいずれのクラスのメンバでもない
スタンドアロン関数である必要があります。
ほかに依存するような関数じゃだめよ!ここから、メンバーにアクセスもできないからね!

dwData 比較関数に渡されるアプリケーション定義の値。
オプションとして引数を一つ取れる様にしといたから勝手に使ってね!(^^)v

解説

アプリケーション定義の比較関数を使ってリストビュー アイテムをソートします。
各アイテムのインデックスは、新しい順序を反映して変更されます。
まぁ、表示ぐらいはやるからさ!

比較関数は次の形式をとります。

int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);

比較関数は、最初のアイテムが 2 番目のアイテムよりも前になると負の値を、
最初のアイテムが 2 番目のアイテムの後にくると正の値を、
2 つのアイテムが等しいときは 0 を返すようにします。
っていう風に作るんだよ!じゃないとソートされないからね!

引数 lParam1 と lParam2 は、比較される 2 つのアイテム データを指定します。
引数 lParamSort は、dwData 値と同じ値です。
*********************************************************************

prev


すばらしい!すごく見やすい!そう思いません?最初からこう書いておいて欲しかった。

さらに解説を進めると、ClistCtrl は自前で比較はやりません! やりたかったら、自前で比較するような関数を作って、自分でソートせい!と言う事です。

関数の構造としては、
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
    //
    // ここでソートする
    //
    return lParam1 < lParam2;//比較した結果を返す。
}

void foo::OnSort()
{
    int itemnum = 1;//別にここは何でもいいです。自由な引数を与えましょう。
    
    m_ListCtrl::SortItems( CompareFunc, itemnum );
}
こうなります。
m_ListCtrl::SortItems()を呼び出すと、現在挿入されているアイテムを2つ摘まんで CompareFunc()に渡します。 それが lParam1とlParam2 ですね。

それだけでは比較するのにデータが足らなくて可哀相かな?ということでおまけで一つ引数があると考えればよいでしょう。

このおまけの型は LPARAM なので32ビット値を渡す事ができます。つまりなんでもありって事ですね。 ポインターだろうがなんだろうが好き勝手に渡しやがれ!こらぁ!ってなもんです。

prev


2つ摘まむ方法は調べたのですが分かりませんでした。 通常はわかりやすいアルゴリズムを用いるはずなのですが、私には分かりませんでした。

つまり、
1
2
3
と言うアイテムが挿入されていたとすると、CompareFunc()は3回呼ばれます。
1, 2
2, 3
1, 3
と言う具合にCompareFunc()に渡り、比較した結果を元に表示だけしてくれます。

当たり前ですが、カラムが複数個存在した場合は例によって「LV_ITEM」構造体がやってきて、いちいちデータを取得して比較したい文字列を取り出した上で比較しなければなりません。 ここまで書いた時点で相当面倒くさい事がご理解いただけるでしょうか?

本当は一回で実装まで解説しようと思ったのだが、えらい事になってしまったので今回はココマデにしたい。 次回は実装編を綴りたい。


antenn-a

prev next


antenn-a