リストビューでアイテムのフィルタリングを行うには?


708  2011-09-13 23:44:08  No: 72905  IP: 192.*.*.*

VisualStudio2008  MFCのリストビューで、あるリストを表示するアプリを作成しています。
例えば下記のようなリストが表示されていた際に、ユーザーが項目①が「りんご」のアイテムのみに絞り込んで見たいと思ったときに、その他のみかんやバナナの行を消さずに非表示にする方法はありませんでしょうか。

番号    項目①    項目②
1      りんご     男
2      みかん     女
3      りんご     女
4      バナナ     女  ・・・

調べたところ、アイテムの検索まではできそうなのですが、アイテムの非表示が調べても見つかりませんでした。
削除ではなく非表示です。
ユーザーの、「今度はみかんだけに絞り込んで見たい」や「全てのアイテムを見たい」という要求に応えるためです。

CListCtrl::SetItemStateでできそうな感じのことが
http://msdn.microsoft.com/ja-jp/library/9t97k8h9(v=VS.90).aspx
に書いてあるのですが、リンク切れのため詳細がわかりません。

どなたかよろしくお願い致します。

編集 削除
仲澤@失業者  2011-09-14 10:47:02  No: 72906  IP: 192.*.*.*

なさそうですね。
LVS_OWNERDRAWFIXEDにして自分で書きましょう。
そうすれば、描画時の文字色も背景色も自由なできます。
もちろん、非表示も。

あと、MSNが一時ダウンしてたようなのでくぐりなおすと
出てくるかもしれません。

編集 削除
gak  2011-09-15 12:52:46  No: 72907  IP: 192.*.*.*

> その他のみかんやバナナの行を消さずに非表示にする方法はありませんでしょうか。
アイテムの非表示というのとは少しアプローチが異なるが、こういう場合は仮想リスト コントロール(LVS_OWNERDATA)が使える。
http://msdn.microsoft.com/ja-jp/library/ye4z8x58%28v=VS.90%29.aspx


class myCListCtrl : public CListCtrl {
    struct ITEM {
        CString col_[2];
        ITEM(LPCTSTR col1, LPCTSTR col2) {
            col_[0] = col1;
            col_[1] = col2;
        }
    };
    std::vector<ITEM> item_;
    std::vector<ITEM*> filtered_;

    void SetData() {
        item_.push_back(ITEM(りんご, 男));
        item_.push_back(ITEM(みかん, 女));
            :
        Filtering();
    }
    void Filtering(LPCTSTR str = NULL, int index = 0) {
        this->SetRedraw(FALSE);
        filtered_.clear();
        for (std::vector<ITEM>::iterator it=item_.begin(); it != item_.end(); ++it) {
            if (str == NULL || it->col_[index] == str) {
                filtered_.push_back(&(*it));
            }
        }
        this->SetItemCount(filtered_.size());
        this->SetRedraw(TRUE);
        this->Invalidate();
    }

    void りんごのみ() {
        Filtering(_T("りんご"), 0);
    }
    void 男のみ() {
        Filtering(_T("男"), 1);
    }
};

BEGIN_MESSAGE_MAP(myCListCtrl, CListCtrl)
   ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
END_MESSAGE_MAP()

void myCListCtrl::OnGetDispInfo (NMHDR* pnmhdr, LRESULT* pResult) {
    LV_DISPINFO* pdi = (LV_DISPINFO *) pnmhdr;
    if ((pdi->item.mask & LVIF_TEXT) != 0) {
        ITEM *item = filtered_[pdi->item.iItem];
        switch (pdi->item.iSubItem) {
            case 0: // 番号
                _stprintf(pdi->item.pszText, _T("%d"), pdi->item.iItem + 1);
                break;
            case 1: // 項目①
            case 2: // 項目②
                _tcscpy(pdi->item.pszText, item->col_[pdi->item.iSubItem - 1]);
                break;
        }
    }
}

編集 削除
708  2011-09-16 01:46:17  No: 72908  IP: 192.*.*.*

お二人ともありがとうございます。
やはり簡単にはできなそうですね。。。

いただいたソースを元にこれから検討していきたいと思います。

編集 削除