| リストビューのアイテムをソートする |
ここでは、以下のようなデータがダイアログ上のリストビューに表示されているものとし、
ダイアログ上の「発売日順」ボタンを1回押すとこれを発売日の古い順(昇順)に並べ替えるものとする。
また、もう1回押すと発売日の新しい順(降順)に並べ替えるものとし、
以後押すたびに昇順、降順交互に並べ替えるものとする。
| 型番 | 発売日 |
|---|---|
| PC-01 | 1999.04.13 |
| PC-01X | 1999.11.15 |
| PC-02 | 1999.09.10 |
まず、必要な関数のヘッダを用意する。リストビューコントロールを貼り付けたダイアログのヘッダファイルに、 以下の処理を記述する。比較関数は、ここではダイアログクラスのstaticメンバ関数として定義する。
// ヘッダファイルでの記述 --------------------
class CMyDlg : public CDialog
{
// 構築
public:
static int CALLBACK CompareFunc(LPARAM param1, LPARAM param2, LPARAM param3);
void RenumberItem();
……
};
次に比較関数の実装を行う。先に説明したように、この関数は1番目と2番目の引数を比較し、
その結果を-1、0、1のいずれかの値で返すという仕様になっているので、当然そのように実装する必要がある。
// ソースファイルでの記述 --------------------
int CALLBACK CMyDlg::CompareFunc(LPARAM param1, LPARAM param2, LPARAM param3)
{
// staticメンバ関数なので、GetParent()で親ウィンドウを取得することはできない
CMyDlg* pDlg = (CMyDlg*)AfxGetMainWnd();
// 比較される2つのアイテムから「発売日」の文字列を取得する
CString str1 = pDlg->m_list1.GetItemText(param1, 1);
CString str2 = pDlg->m_list1.GetItemText(param2, 1);
// strcmpを使うなら、降順の場合はstr1とstr2を逆にしなければならない
int iReturn;
if( !param3 )
iReturn = strcmp( str1, str2 ); // 昇順
else
iReturn = strcmp( str2, str1 ); // 降順
return iReturn;
}
比較関数の定義のところを見ればわかるのだが、アイテムを入れ替える場合には比較関数で1を返すようにしなければならない。
strcmp関数を使う場合は、この関数の第1引数の方が大きい場合に1を返すよう注意すること。比較関数ができたので、あとはSortItems関数でこれを呼べばよいのだが、実はそれだけでは正しくソートできない。 SortItems関数を呼ぶ前には、必ずアイテムに対しそれが並んでいる順番に番号をつけていかなければならないのである。 この処理は、ヘッダの部分で定義したRenumberItem関数がその役目を果たす。以下のように実装する。
// ソースファイルでの記述 --------------------
void CMyDlg::RenumberItem()
{
LV_ITEM lvItem;
// m_list1はCListCtrl型のDDX変数で、ソートを行うリストビューコントロールのオブジェクトであるものとする
for( int i = 0; i < m_list1.GetItemCount(); i++ ) {
lvItem.iItem = i;
lvItem.iSubItem = 0;
lvItem.mask = LVIF_PARAM;
lvItem.lParam = i; // ここで番号をアイテムに指定する
m_list1.SetItem(&lvItem);
}
}
ここまでできたら、あとは「発売日」ボタンが押されたときの処理を実装すればよい。
この場合ハンドラ関数の実装を以下に記述する。
// ソースファイルでの記述 --------------------
void CMyDlg::OnButton1()
{
// TODO: この位置にコントロール通知ハンドラ用のコードを追加してください
RenumberItem(); // SortItems関数を呼び出す前には必ず実行
static BOOL bSort = FALSE; // staticで定義すること
m_list1.SortItems(CompareFunc, bSort);
bSort = !bSort; // bSortがFALSEならTRUE、TRUEならFALSEにする
}
SortItems関数の第2引数に指定したbSortの値は、比較関数CompareFuncの3番目の引数param3に渡される。
つまり、1回目はbSortの値がFALSEなのでparam3もFALSE(すなわち0)となり、昇順ソートが行われる。
また2回目はbSortがTRUEになっているのでparam3もTRUE(非0)となり、降順でソートされるというわけである。