オーナードローで複数行リストボックスを作成する

オーナードローを利用して、各項目が複数行で表示できるようなりストボックスを作成してみる。
  1. リソースエディタでダイアログにリストボックスを貼り付ける。

  2. リストビューのプロパティで「オーナー描画」を「可変」にする。さらに「文字列あり」をチェックする。
    「文字列あり」をチェックすると、リストビューにLBS_HASSTRINGS属性がつく。 この属性をつけないと、オーナードローリストボックスでCListBox::GetText関数が有効にならない。

  3. CListBoxクラスの派生クラスを定義する。
    「挿入」−「クラスの新規作成」メニューでクラスの新規作成ダイアログを開く。 クラス名をCMultiLinesListBox、基本クラスをCListBoxにする。

  4. このクラスにDrawItem関数をオーバーライドさせる。

  5. ClassWizardで、CMultiLinesListBoxクラスのDDX変数を作成する。
    「表示」−「ClassWizard」メニューでClassWizardダイアログを開く。 「メンバ変数」タブを選択し、「クラス名」を「CMultiLinesListDlg」にして、 「コントロールID」でIDC_LIST1を選択し「変数の追加」ボタンを押す。
    メンバ変数の追加ダイアログが表示されたら、変数名をm_list1、カテゴリをコントロール、 変数のタイプをCMultiLinesListBoxにしてOKボタンを押す。
    この後ダイアログクラス(リストボックスを貼り付けたウィンドウ)のヘッダファイルを開き、 "MultiLinesListBox.h"をインクルードする。

  6. リストボックスにアイテムを最低1つ挿入する。
    ダイアログクラスのOnInitDialog関数で、以下のように処理する。 強制的に改行させる場合は文字列内に"\n"を挿入する。
    	BOOL CMultiLinesLBDlg::OnInitDialog()
    	{
    		CDialog::OnInitDialog();
    	(中略)
    		// TODO: 特別な初期化を行う時はこの場所に追加してください。
    		m_list1.AddString("エルコンドルパサー\n  NHKマイルC、ジャパンカップ、サンクルー大賞");
    		m_list1.AddString("スペシャルウィーク\n  日本ダービー、天皇賞春、天皇賞秋、ジャパンカップ");
    		m_list1.AddString("グラスワンダー\n  朝日杯3歳S、有馬記念、有馬記念、宝塚記念");
    
    		return TRUE;  // TRUE を返すとコントロールに設定したフォーカスは失われません。
    	}
    	
  7. CMultiLinesListBox::DrawItem関数内の処理を記述する。
    	void CMultiLinesListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
    	{
    		// TODO: 指定されたアイテムを描画するためのコードを追加してください
    		CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    		CString str;
    		CRect rect;
    
    		// 項目の文字列と外接四角形の取得
    		//   オーナー描画の場合、GetTextはLBS_HASSTRINGS属性が有効な場合のみ使用可
    		GetText(lpDrawItemStruct->itemID, str);
    		rect = lpDrawItemStruct->rcItem;
    
    		// 背景色の描画
    		//   選択項目の場合は選択色で描く
    		if( lpDrawItemStruct->itemState & ODS_SELECTED )
    		{
    			pDC->FillSolidRect(&rect, ::GetSysColor(COLOR_HIGHLIGHT));
    		}
    		else
    		{
    			pDC->FillSolidRect(&rect, ::GetSysColor(COLOR_WINDOW));
    		}
    
    		//   フォーカスがある場合にはフォーカス四角形を描く
    		if( lpDrawItemStruct->itemState & ODS_FOCUS )
    			pDC->DrawFocusRect(&rect);
    
    		// 文字列の描画
    		//   DrawTextにDT_CALCRECT属性をつけるとCRectの高さを複数行の文字列に
    		//   合わせて変更する(描画はおこなわない)
    		rect.InflateRect(-1, -1);
    		pDC->DrawText(str, &rect, DT_LEFT | DT_WORDBREAK | DT_CALCRECT);
    		pDC->DrawText(str, &rect, DT_LEFT | DT_WORDBREAK);
    	}
    	
ここまでできたら一旦ビルドし、実行してみる。表示された項目を見ると、 おそらく項目の高さがおかしくなっていて文字列が適切に表示されないだろう。 この場合はCMultiLinesListBoxクラスのMeasureItem関数をオーバーライドし、次のように処理する。
void CMultiLinesListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
	// TODO: 指定されたアイテムのサイズを調べるためのコードを追加してください
	lpMeasureItemStruct->itemHeight = 40;	// 数値は適当な値にする
}

目次へ