一覧表を表示するコントロールであるリストビュー(CListCtrlクラス)について、最低限の基本的な使い方についてメモ。
開発環境 | Visual Studio 2022 |
---|---|
言語 | C++ |
フレームワーク | MFC |
動作確認 | Windows 11 Windows 10 Windows 7 |

前提条件
- ツールボックスより、「List Control」をダイアログに貼る
- プロパティの「ビュー」は、「レポート」を設定
- ダイアログクラスにメンバー変数追加
CListCtrl m_list;
DDX_Control(pDX, IDC_LIST1, m_list);
拡張スタイルの設定
OnInitDialogの「// TODO: 初期化をここに追加します。」より後に記述。 設定したいスタイルをOR条件で指定する。
m_list.SetExtendedStyle(m_list.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
- GetExtendedStyleは、現状の設定の取得
- LVS_EX_FULLROWSELECTは、テキスト選択時、1行まるごと反転する。 これを設定しない場合、一番左側の列のみ反転になる
- LVS_EX_GRIDLINESは、グリッド線の設定
- リストビューからフォーカスが外れた場合でも選択状態を維持するには、プロパティの「選択を常に表示」をTrueに設定する



列の挿入
最初に列を挿入してから、次に行を挿入する。
m_list.InsertColumn(列のインデックス, ヘッダーのテキスト, 配置, 列幅の初期値);
- 「列のインデックス」は、ゼロ開始(以下、インデックスは行・列ともにゼロ開始)
- 「ヘッダーのテキスト」の文字コードは、UTF-16
- 「配置」は、LVCFMT_LEFT(左寄せ)、LVCFMT_RIGHT(右寄せ)、LVCFMT_CENTER(中央寄せ)
- 「列幅の初期値」の単位は、ピクセル
- 型はリファレンスを参照のこと
上記の方法では、LVCFMT_RIGHTまたはLVCFMT_CENTERを指定した場合でも、一番左側の列は左寄せになる。 一番左側の列を右寄せ、または、中央寄せにする方法は、 「リストビューの列の属性を変更する」を参照のこと。
テキストの設定
// iLine 行のインデックス(ゼロ開始)
// iCol 列のインデックス(ゼロ開始)
// data 表示するテキスト(UTF-16)
void CXxxxDlg::setItemListView(const int iLine, const int iCol, wchar_t *data)
{
LVITEM lvItem{};
lvItem.mask = LVIF_TEXT;
lvItem.iItem = iLine;
lvItem.iSubItem = iCol;
lvItem.pszText = data;
if (iCol == 0)
{
// 行の挿入と、最初の列にテキスト設定
m_list.InsertItem(&lvItem);
}
else
{
// 最初以外の列にテキスト設定
m_list.SetItem(&lvItem);
}
}
列幅の自動調整
// ヘッダーのテキストの幅に合わせる(列の挿入後に記述)
m_list.SetColumnWidth(列のインデックス, LVSCW_AUTOSIZE_USEHEADER);
// ヘッダー以外のテキストの最大幅に合わせる(テキスト設定後に記述)
m_list.SetColumnWidth(列のインデックス, LVSCW_AUTOSIZE);
テキストのフォーカスと選択

フォーカスは、1行のみで、テキストの周りが点線で囲まれる。 選択は、複数行可能で、テキストの背景の色が反転する。 複数行選択した場合、最後に選択した行にフォーカスが移動する。
// フォーカスと選択を同時に設定する例
m_list.SetItemState(行のインデックス, LVIS_FOCUSED | LVIS_SELECTED,
LVIS_FOCUSED | LVIS_SELECTED);
- 2番目の引数は設定値(ビット)、3番目の引数はどのビットを設定するかのマスク
- フォーカスはLVIS_FOCUSED、選択はLVIS_SELECTED
テキストのフォーカスと選択を解除
逆にゼロを設定する(ビットを落とす)とよい。
// 全行のフォーカスと選択を解除する例
for (int i = 0; i < m_list.GetItemCount(); i++)
{
m_list.SetItemState(i, 0, LVIS_FOCUSED | LVIS_SELECTED);
}
フォーカスがある行のインデックスを取得
(1) ダイアログクラスにメンバー関数を追加。(関数名は任意)
void OnItemChanged(NMHDR *pNMHDR, LRESULT *pResult);
(2) メッセージマップに、以下を追加。
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnItemChanged)
(3) メンバー関数を記述。 リストビューにメッセージが飛ぶ(マウスや矢印キーでテキスト選択)度に、この関数が呼ばれる。
void CXxxxDlg::OnItemChanged(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLISTVIEW *pListView = reinterpret_cast<NMLISTVIEW *>(pNMHDR);
if (pListView->uChanged & LVIF_STATE)
{
if (pListView->uNewState & LVIS_FOCUSED)
{
// pListView->iItemに、フォーカスがある行のインデックスが入っている
//
//
//
}
}
*pResult = 0;
}
選択行のインデックスを取得
// 最初の選択行の位置を取得
POSITION pos = m_list.GetFirstSelectedItemPosition();
if (pos == nullptr)
{
// 選択行無し
}
else
{
while(pos)
{
// 現在の選択行のインデックスと、次の選択行の位置を取得
int nLine = m_list.GetNextSelectedItem(pos);
// nLineに選択行のインデックスが入っている
//
//
//
}
}
全行削除
m_list.DeleteAllItems();
全列削除
DeleteColumnの引数はインデックスなので、ゼロを列数分だけ削除すると全列削除になる。 (削除した列より後ろのインデックスは1個前にずれるため)
// 列数の取得
int nColumnCount = m_list.GetHeaderCtrl()->GetItemCount();
// 削除
for (int i = 0; i < nColumnCount; i++)
{
m_list.DeleteColumn(0);
}
リファレンス
CListCtrl Class
https://learn.microsoft.com/en-us/cpp/mfc/reference/clistctrl-class
(おまけ)サンプルデータ
const std::vector<std::vector<std::wstring>> data
{
{L"茨城県", L"水戸市", L"笠原町"},
{L"栃木県", L"宇都宮市", L"塙田"},
{L"群馬県", L"前橋市", L"大手町"},
{L"埼玉県", L"さいたま市", L"浦和区"},
{L"千葉県", L"千葉市", L"中央区"},
{L"東京都", L"新宿区", L"西新宿"},
{L"神奈川県", L"横浜市", L"中区"}
};