antenn-a
company profile

MFC航海日記 三十三日(CListCtrlでアイテムの削除)

アイテムの挿入が出来たのだから、アイテムの削除ができなきゃいかん!
というわけで、今回は「アイテムの削除」をやります。

私個人の意見としては、「CListCtrlは使いにくい!!」という事である。 従って、今現在 CListCtrlを継承した EListCtrl クラスを作成中である。

どのあたりが「使いにくい」かというと、例えば「現在選択されているアイテムのインデックスを返す関数」が無いのである。

CListBox::GetSel()にあたる関数が無い為、現在どのアイテムが選択されているかを調べたい場合、自前で調べるしかないのである。

prev


調べかただが、これまた面倒くさいのである。 まぁ、そろそろ覚悟は出来ていると思うが、またしても「LV_ITEM」を使う事になる。

CListCtrlを実装しようとした場合、「LV_ITEM」とは縁を切れないらしい (^^;

実装する前に概要だが、非常にシンプルである (^^;
  1. LV_ITEMのオブジェクトのマスクにアイテムの状態を表すフラグを立てておく。
  2. リストコントロールの最初のアイテムから最後のアイテムまで一件ずつ検索し、選択されているかどうかを確かめる。
  3. 選択されていたら消す!
以上の作業になる。

とても高等なクラスとは思えない、素敵な仕様になっている。

prev


実装は簡単なのだが、簡単だからそクラスの中にパッケージしてほしかったと思う。
void foo::DeleteItem()
{
    if( m_LstCtrl.GetSelectedCount() == 0 ){ 
        AfxMessageBox( "No items selected." );
        return;
    }

    // delete all selected items
    LV_ITEM     item;
    int         nIdx;

    memset( &item, 0, sizeof( item ) );
    item.mask = LVIF_STATE;
    item.stateMask = LVIS_SELECTED;
    //最後から検索!ここがミソ
    for( nIdx = m_LstCtrl.GetItemCount(); nIdx >= 0; nIdx-- ){
        item.iItem = nIdx;
        m_LstCtrl.GetItem( &item );
        if( item.state == LVIS_SELECTED )
            m_LstCtrl.DeleteItem( nIdx );
    }
}
上記のソースコードで選択されているアイテムの削除が可能であるが、for ループの直前のコメントに注目して欲しい。

「最後から検索!ここがミソ」と書いてある。 そのとおり!ここがミソなのである。

(プログラム中級者以上の方は見なくていいです)
どうミソかというと、アイテムを削除するとインデックスが入れ替わる為消していくと変になってしまうのです。 従って最後から削除しないとおかしな事になります。

言っている意味分かりますか?

0 test0
1 test1
2 test2
3 test3
4 test4
左側がインデックス、右側が名前というようなテーブルを考えた時、test1,test2 だけ削除しようとしましょう。 すると、
0 test0 <- 通過
1 test1 <- 削除
となって
0 test0
1 test2
2 test3
3 test4
となりますね。 for ループで削除しますから、次の番号は 2 (インデックスで)ですから test3 になってしまいます。 すると・・・test2 は削除できませんでした。

となります。

prev


これを回避する為には、最後から削除しなければならないわけです。 分かりましたか?

さて、今回はアイテムの削除を学びました(私が) 次回は何をしようかな?



antenn-a

prev next


antenn-a