オーナードローリストビュー


オーナードローリストビューの作成

オーナードローリストビューを作成するには、次の手順が必要である。
  1. リソースエディタでリストビュー(レポート形式)を作成する。
  2. リストビューのプロパティで「オーナー描画固定」をチェックする。
  3. CListCtrlクラスの派生クラスを定義する。
  4. このクラスにDrawItem関数をオーバーライドさせる。
  5. リストビューにアイテムを最低1つ挿入する。
  6. ClassWizardで、リストビューのオブジェクトを作成し、それを派生クラスのオブジェクトに置きかえる。

DrawItem関数のオーバーライド
CListCtrlの派生クラスではなぜかClassWizardでこの関数をオーバーライドさせることができない。 そこで直接ソースに記述する。

	// ヘッダファイルでの記述 --------------------
	// オーバーライド
	// ClassWizard は仮想関数のオーバーライドを生成します。
	//{{AFX_VIRTUAL(CDeriveListCtrl)
	public:
	virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
	//}}AFX_VIRTUAL

	// ソースファイルへの記述 --------------------
	void CDeriveListCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
	{
		……
	}
アイテムの挿入
アイテムの挿入は通常の場合と同じ。ただし画面上では何も表示されない。 また、アイテムを挿入していないとDrawItem関数が呼び出されないので注意すること。

実際の描画処理
オーナードローでは描画処理を記述する必要がある。 DrawItem関数内で、以下のように処理する。
	void CDeriveListCtrl::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct )
	{
		CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
		……
	}
オブジェクトの置き換え
ClassWizardを使って、コントロールのオブジェクトを作成することができる。
ClassWizardの「メンバ変数」タブで、リストビューのコントロールIDを選択し、「変数の追加」ボタンを押す。 「カテゴリ」を"コントロール"にすると、変数のタイプが"CListCtrl"になっているはずなので、ここを 自分が作成したCListCtrlの派生クラスに変更してやればよい。こうしてメンバ変数を作成すれば、 最初にリソースエディタで作成したリストビューは、CListCtrlでなくその派生クラスのオブジェクトになるのである。

目次へ



オーナードローリストビューでアイテムの高さを変更する

オーナードローリストビューでフォントを変更しても、アイテムの高さが変わらないため不具合が起きる。 これを解決するために、以下の手順を踏み修正する必要がある。


  1. オーナードローリストビューを作成する
    作成方法についてはオーナードローリストビューの作成を参照のこと。

  2. リストビューのフォントを変更する
    リストビューを貼りつけたダイアログの親ウィンドウで行う。この方法については コントロールのフォントを変更するを参照のこと。

  3. リストビュークラスでCDialog::OnSetFont関数をオーバーライドさせる
    残念ながらClassWizardを使ってオーバーライドさせることができないので、自分で記述しなければならない。
    	// リストビュークラスのヘッダーへの記述
    	class CMyListCtrl : public CListCtrl
    	{
    	…… 
    		// 生成されたメッセージ マップ関数
    	protected:
    		//{{AFX_MSG(CMyListCtrl)
    		afx_msg LRESULT OnSetFont(WPARAM wParam, LPARAM lParam);
    		//}}AFX_MSG
    	……
    	};
    
    	// リストビュークラスのソース内のメッセージマップへの記述
    	BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
    		//{{AFX_MSG_MAP(CMyListCtrl)
    		ON_MESSAGE(WM_SETFONT, OnSetFont)
    		//}}AFX_MSG_MAP
    	END_MESSAGE_MAP()
    
    	// OnSetFont関数の実装
    	LRESULT CMyListCtrl::OnSetFont(WPARAM wParam, LPARAM lParam)
    	{
    		LRESULT res =  Default();
    
    		CRect rc;
    		GetWindowRect( &rc );
    
    		WINDOWPOS wp;
    		wp.hwnd = m_hWnd;
    		wp.cx = rc.Width();
    		wp.cy = rc.Height();
    		wp.flags = SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER;
    		SendMessage( WM_WINDOWPOSCHANGED, 0, (LPARAM)&wp );
    
    		return res;
    	}
    
  4. リストビュークラスで返送メッセージハンドラであるMeasureItem関数を定義する。
    これも、全て自分で記述する必要がある。
    	// リストビュークラスのヘッダーへの記述
    	// オーバーライド
    		// ClassWizard は仮想関数のオーバーライドを生成します。
    		//{{AFX_VIRTUAL(CMyListCtrl)
    		virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
    		virtual void MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct );
    		//}}AFX_VIRTUAL
    
    	// リストビュークラスのソース内のメッセージマップへの記述
    	BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
    		//{{AFX_MSG_MAP(CMyListCtrl)
    		ON_MESSAGE(WM_SETFONT, OnSetFont)
    		ON_WM_MEASUREITEM_REFLECT()
    		//}}AFX_MSG_MAP
    	END_MESSAGE_MAP()
    
    	// MeasureItem関数の実装
    	void CMyListCtrl::MeasureItem( LPMEASUREITEMSTRUCT lpMeasureItemStruct )
    	{
    		LOGFONT lf;
    		GetFont()->GetLogFont( &lf );
    
    		if( lf.lfHeight <0 )
    			lpMeasureItemStruct->itemHeight = -lf.lfHeight; 
    		else
    			lpMeasureItemStruct->itemHeight = lf.lfHeight; 
    	}
    
親ウィンドウクラスにおいて、フォント変更のためにCWnd::SetFont関数を呼び出している。 これによってリストビューに対しWM_SETFONTメッセージが送信されるので、 これをリストビューのOnSetFont関数で拾っている。
この関数内ではWM_WINDOWPOSCHANGEDメッセージが発行されているが、 これによって親ウィンドウへWM_MEASUREITEMが発行される。本来このメッセージは親ウィンドウで処理するが、 子コントロールに返送メッセージハンドラを定義することで親から返送されたメッセージを処理することができる。 この中でMEASUREITEMSTRUCT構造体のitemHeightメンバの値を変更することで、 アイテムの高さを変更することができるのである。

目次へ