[kaze's test] プログラミングメモ →目次


CListCtrlのサブアイテム文字列編集

  Excelのようにレポート用のCListCtrlをExcelのようにアイテム及びサブアイテムを編集する方法の一つです。

 

  レポート表示用のListCtrlをDialogに貼り付けて、列と行を適当に作成しておきます。ListCtrlのセルをダブルクリックすると、そのセルの上にエディットを出して編集します。編集後に編集結果をセルに書き戻します。
 処理の流れは、下記に記述します。

1.ListCtrlをダブルクリックすると、ダブルクリック場所のItemとSubItemのインデックスを求めます。

2.ItemインデックスとSubItemインデックスで、セルの外接する四角形(CRect)を求めます。

3.ListCtrlの子ウィンドウとして、CEditをセルの真上で作成し、セ ルの文字列を当CEditに設定します。

4.CEditのフォーカスを失うイベントハンドルOnKillFocusで、CEditの文字列をセルに逆設定し、CEditのウィンドウを廃棄します。 

ソースコード:

下記に列挙しているソースは、CTestDlg、CListCtrlWithEdit、CEditInListCtrlクラスの関係部分だけです。
class CTestDlg : public CDialogEx
{
    // 省略
    CListCtrlWithEdit m_listctrl;
    // 省略
}
BOOL CTestDlg::OnInitDialog()
{
    // 省略
    CDialogEx::OnInitDialog();
    m_listctrl.SetExtendedStyle(m_listctrl.GetExtendedStyle() 
                                | LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    // 省略
}

void CTestDlg::OnNMDblclkListCells(NMHDR *pNMHDR, LRESULT *pResult)
{
   LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR);
   *pResult = 0;
   (pNMItemActivate->iItem < 0 || pNMItemActivate->iSubItem < 1)
        return;
   m_listctrlCells.BeginEdit(pNMItemActivate->iItem, 
                             pNMItemActivate->iSubItem);
}

class CListCtrlWithEdit : public CListCtrl
{
    // 省略
    CEditInListCtrl m_Edit;
    void BeginEdit(int iItem, int iSubItem);
    // 省略
};

#define IDC_EDIT_SUB_ITEM 1234
void CListCtrlWithEdit::BeginEdit(int iItem, int iSubItem)
{
    CRect ColumnRect;
    
    if (iSubItem == 0)
        GetSubItemRect(iItem, iSubItem, LVIR_LABEL, ColumnRect);
    else
        GetSubItemRect(iItem, iSubItem, LVIR_BOUNDS, ColumnRect);

    ColumnRect.DeflateRect(1,1);
    m_Edit.Create(WS_VISIBLE | ES_AUTOHSCROLL | ES_LEFT, 
                  ColumnRect,  this, IDC_EDIT_SUB_ITEM);
    CFont* pFont = GetFont();
    m_Edit.SetFont(pFont);
    m_Edit.m_row = iItem;
    m_Edit.m_col = iSubItem;
    m_Edit.SetWindowText(GetItemText(iItem, iSubItem));
    m_Edit.SetFocus();
}

class CEditInListCtrl : public CEdit
{
    // 省略
    int m_row;
    int m_col;
    afx_msg void OnKillFocus(CWnd* pNewWnd);
    // 省略
};

void CEditInListCtrl::OnKillFocus(CWnd* pNewWnd)
{
    CEdit::OnKillFocus(pNewWnd);
    if (m_row >= 0 && m_col >= 0)
    {
        CString strText;
        GetWindowText(strText);
        ((CListCtrl*)GetParent())->SetItemText(m_row, m_col, strText);
    }
    DestroyWindow();
}