リストビューにアイテムを追加するには?

解決


Ris  2008-02-18 01:54:17  No: 67535

宜しくお願いします。
環境はVC++6.0 MFC ダイアログベース、です。

ボタンを押すと、関連するアイテムをリストビューに表示したいのですが、
アイテムが一番左しか表示されません。
しかも2回目を押すと、何も表示されなくなってしまいます。
(リストビューはレポート形式です)

どこか間違えているのだと思いますが、どこか分からず困っています。
宜しければご教示お願いしますm(_ _)m

// 使うクラス(適切な値が入っています)

CListCtrl* pListCtrl;    // リストビュークラスのポインタ
CStringArray itemArray;  // ヘッダ配列
CMapStringToOb itemMap;  // CString がキーであるCStringArrayのアイテム配列
CStringArray idArray;    // マップ用のキー配列

// ヘッダを削除する

CHeaderCtrl* headerCtrl = pListCtrl->GetHeaderCtrl();

for (i = 0, j = headerCtrl->GetItemCount(); i < j; i ++) {
  headerCtrl->DeleteItem(itemId);
}

// アイテムを削除する

pListCtrl->DeleteAllItems();

// ヘッダを作成する

HDITEM hdItem;
hdItem.mask = LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH;
hdItem.fmt  = LVCFMT_CENTER;
hdItem.cxy  = 48;

for (i = 0, j = itemArray.GetSize(); i < j; i ++) {
  CString item = itemArray.GetAt(i);

  hdItem.pszText = item.GetBuffer(item.GetLength() + 1);
  headerCtrl->InsertItem(i, &hdItem);

  item.ReleaseBuffer();
}

// アイテムを作成する

LVITEM lvItem;
lvItem.mask = LVIF_PARAM | LVIF_TEXT;

for (i = 0, j = idArray.GetSize(); i < j; i ++) {

  CObject* pObject;
  itemMap.Lookup(idArray.GetAt(i), pObject);

  lvItem.iItem  = i;
  lvItem.lParam = i;

  for (int p = 0, q = ((CStringArray *)pObject)->GetSize(); p < q; p ++) {

    CString item = ((CStringArray *)pObject)->GetAt(p);
    int length = item.GetLength();

    lvItem.cchTextMax = length;
    lvItem.pszText    = item.GetBuffer(length + 1);
    lvItem.iSubItem   = p;

    if (! p) {
      pListCtrl->InsertItem(&lvItem);
    } else {
      pListCtrl->SetItem(&lvItem);
    }
    
    item.ReleaseBuffer();

  }
}

ヘッダはしっかりと表示出来ていますが、
headerCtrl ではなく、pListCtrl からアイテムを追加すると、
一度だけ正常にアイテムが表示されます。

しかし、すみませんが、
問題の原因と関係あるのか分からないのです。


Ris  2008-02-18 01:58:16  No: 67536

ミスがありました、申し訳ありません。

headerCtrl->DeleteItem(itemId);
は間違いで、正しくは
headerCtrl->DeleteItem(0);
です。

あとインデントが消えてしまって見辛いのですが、
宜しくお願いします。


シャノン  2008-02-18 20:25:53  No: 67537

> HDITEM hdItem;
> hdItem.mask = LVCF_TEXT | LVCF_FMT | LVCF_SUBITEM | LVCF_WIDTH;
> hdItem.fmt  = LVCFMT_CENTER;

HDITEM と LVCOLUMN を混同しないでくださいね。

> hdItem.pszText = item.GetBuffer(item.GetLength() + 1);

些細な問題ですが、
hdItem.pszText = const_cast< LPTSTR >( static_cast< LPCTSTR >( item ) );
とでもすべきかと。

> lvItem.cchTextMax = length;

アイテムの追加時にはこのメンバを設定する必要はありません。

> lvItem.pszText    = item.GetBuffer(length + 1);

上に同じく、GetBuffer の使用は適切ではありません。

> if (! p) {
> pListCtrl->InsertItem(&lvItem);
> } else {
> pListCtrl->SetItem(&lvItem);
> }

たぶんここが最大の問題ですが、InsertItem と SetItem が逆ではありませんか?


ris  2008-02-19 08:43:19  No: 67538

シャノンさん返信ありがとうございます。
見事解決することが出来ました!

また

> HDITEM と LVCOLUMN を混同しないでくださいね。
> const_cast< LPTSTR >( static_cast< LPCTSTR >( item ) );
> アイテムの追加時にはこのメンバを設定する必要はありません。

すべてにのご指摘、とても勉強になりました。
特にCStringからのキャストは感動的でした。
調べていてGetBufferメソッドを見つけたので使っていた次第です。

ところで、
> InsertItem と SetItem が逆
これは逆ではないような気がします。

サンプルを読んでいて
アイテム追加(InsertItem)⇒アイテム設定(SetItem)
のように設定すればよいと把握しております。
※「for (int p = ・・・」のループの1回目だけinsertで残りはsetしています。

それでその後も色々と試していたのですが、
どうやら SetItem 時には lvItem.mask にLVIF_PARAM を含ませては
ならないらしいことが分かりました。

それを取ると、正常に動作致しました。

全項目に対してソートを実装しているので、サブアイテムにもLVIF_PARAMが
必要だろうと勘違いしておりました。

大変いい勉強になりました。
どうもありがとうございますm(_ _)m

今後も宜しくお願い致します。


シャノン  2008-02-19 10:00:29  No: 67539

> これは逆ではないような気がします。

うん、ごめん。俺の勘違いです。
個人的に、整数やポインタに対して ! っていう書き方はしないので読み間違えました。

> どうやら SetItem 時には lvItem.mask にLVIF_PARAM を含ませては
> ならないらしいことが分かりました。

俺は全然お役に立てませんでしたorz

参考までに、MSDNから引用。

> To set the text of a subitem, set the iItem and iSubItem members to indicate the specific subitem, and use the pszText member to specify the text.
> Alternatively, you can use the ListView_SetItemText macro to set the text of a subitem. You cannot set the state or lParam members for subitems because subitems do not have these attributes.

http://msdn2.microsoft.com/en-us/library/bb775091.aspx

ばっちり書いてありました。


ris  2008-02-19 16:32:23  No: 67540

解決のチェック付け忘れてました(汗

> 俺は全然お役に立てませんでした

そんなことないです。
シャノンさんのおかげで、アイテムを作るところに問題がある
ことが分かりました。

> ばっちり書いてありました。

MSDNも調べたつもりだったのですが、調べ不足でした。すみません。

あとintに対しての ! 演算子使うべきではありませんでした。
特に質問する掲示板で。

スマートに書こうと思ってこうなってしまいました。
以後気を付けたいと思います。

どうもありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加