オーナードロー(CListCtrl編)

オーナードローを利用すると、各コントロールのビジュアルをカスタマイズできてステキです。
CListCtrlでは、Create()関数でスタイルを設定するときにLVS_OWNERDRAWFIXEDを設定します。
ちなみにレポートビューの場合のみなので注意。
スタイルを設定したらDrawItem()関数をオーバーライドしなければなりません。
この関数は、オーナードローが起きた場合に呼び出される関数で、この関数に描画等の処理を 書かなくてはなりません
DrawItem()関数
virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct );
名前 説明
lpDrawItemStruct 要求された描画の型についての情報を持つ DRAWITEMSTRUCT 構造体への long ポインタ。
この関数は、アイテムに付き1回呼ばれます。
引数のlpDrawItemStructには描画に関する情報が詰まっています。
この引数を元に描画を行います。
DRAWITEMSTRUCT構造体
typedef struct tagDRAWITEMSTRUCT { UINT CtlType; UINT CtlID; UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; ULONG_PTR itemData; } DRAWITEMSTRUCT;
名前 説明
CtlType コントロールの種類
CtlID コントロール ID
itemID LVITEMのiItemに相当する
itemAction 要求される描画動作
itemState 項目の表示状態
hwndItem ウィンドウ ハンドル
hDC アイテムのデバイスコンテキスト
hDC アイテムのデバイスコンテキスト
rcItem アイテムのサイズ
itemData リスト渡された値
ちなみにこの構造体、リストのほかにコンボボックス等項目のあるコントロールでも利用されるようです。

で、描画するには描画先を取得しなければなりません。

CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);


これでデバイスコンテキストをCDC型のオブジェクトのポインタに変更します。
あとは、rcItemやGetItem()を利用して描画するだけ。
フォーカスがある場合は選択状況も反映することを忘れないように。
あと、チェックボックスは、

GetImageList(LVSIL_STATE);


でイメージリストを取得します。
これは状態を表すイメージリストを取得する意味です。
で、イメージリストの0番にはチェックのないチェックボックス、1番にはチェックされたチェックボックスの イメージか格納されているので、GetCheck()関数で状態を取得して表示します。
ま、とりあえず例を・・・(手抜きな感じもありますが許してくだされ)
CListCtrlのオーナードローの例
void CListTest::DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ){
    // 再描画するItemの座標を取得
    CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

    CRect rect(lpDrawItemStruct->rcItem);
    int iItem = lpDrawItemStruct->itemID;

    _TCHAR szBuff[MAX_PATH];

    LVITEM lvItem;
    int iCnt = 0;
    CRect iRect;

    //フォーカスがあるかどうか
    BOOL isForcus = GetItemState(iItem, LVIS_FOCUSED) == LVIS_FOCUSED;

    int iIndentPix;
    int iIndent;
    CHeaderCtrl *Head = GetHeaderCtrl();
    int iMax = Head->GetItemCount();

    while(iMax > iCnt){
        //出力座標の初期化
        iIndentPix = 0;

        //アイテム取得のための設定
        lvItem.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE | LVIF_INDENT;
        lvItem.iItem = iItem;
        lvItem.iSubItem = iCnt;
        lvItem.pszText = szBuff;
        lvItem.cchTextMax = sizeof(szBuff);
        lvItem.stateMask = LVIS_ACTIVATING | LVIS_FOCUSED | LVIS_SELECTED | LVIS_STATEIMAGEMASK;


        if (GetItem(&lvItem) == TRUE){
            iIndent = lvItem.iIndent;
            if(iCnt == 0){
                //アイテムの場合
                GetItemRect(iItem, &iRect, LVIR_BOUNDS);

                //インデント分の座標計算
                iIndentPix = (iIndent > 0) ? iIndent * 16 : 0;

            }else{
                //サブアイテムの場合
                GetSubItemRect(iItem, iCnt, LVIR_BOUNDS, iRect);
            }

            //選択状態か
            DWORD txtColor = ::GetSysColor(COLOR_WINDOWTEXT);
            BOOL isSelect = FALSE;
            if(GetItemState(iItem, LVIS_SELECTED) == LVIS_SELECTED){
                pDC->FillRect(iRect, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
                txtColor = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
                isSelect = TRUE;
            }else{
                pDC->FillRect(iRect, &CBrush(::GetSysColor(COLOR_WINDOW)));
            }

            //フォーカスがあるか
            if(GetItemState(iItem, LVIS_FOCUSED) == LVIS_FOCUSED){
                CPen pen(PS_DOT, 1, ::GetSysColor(COLOR_BTNFACE));
                pDC->SelectObject(pen);
                CPoint pos[5];
                pos[0].x = iRect.left + 1;
                pos[0].y = iRect.top;

                pos[1].x = iRect.right - 2;
                pos[1].y = iRect.top;

                pos[2].x = iRect.right - 2;
                pos[2].y = iRect.bottom - 2;

                pos[3].x = iRect.left + 1;
                pos[3].y = iRect.bottom - 2;

                pos[4].x = iRect.left + 1;
                pos[4].y = iRect.top;
                pDC->Polyline(&pos[0], 5);
                pen.DeleteObject();
            }


            pDC->SetTextColor(txtColor);
            DWORD uFlag = DT_WORD_ELLIPSIS | DT_SINGLELINE ;

            //m_arrAttr はテキストの表示位置を格納しているCArrayのリスト
            if(m_arrAttr.GetSize() > iCnt){
                PLV_ATTRIBUTE attr = (PLV_ATTRIBUTE)m_arrAttr.GetAt(iCnt);
                switch(attr->dwAligne){
                case LVAL_CENTER:
                    uFlag |= DT_CENTER;
                    break;
                case LVAL_RIGHT:
                    uFlag |= DT_RIGHT;
                    break;
                default:
                    uFlag |= DT_LEFT;
                    break;
                }
            }else{
                uFlag |= DT_LEFT;
            }

            CRect strRect;
            strRect = iRect;
            strRect.left += 2;

            CString outText = lvItem.pszText;
            pDC->DrawText(outText,
                          strRect, uFlag);
        }
        iCnt++;
    }
}