自分用メモ　-ダブルクリックでサブアイテム入力 CListCtrl-

今更ながら、MFCの使用方法のメモです。Visual Studio 2015で作成しました。


MSFlexGridを使用して入力していたアプリを更新するために作成しました。
CListCtrlのセルをダブルクリックするとCEditで編集して、リターンもしくはフォーカスを失うとセルに書き出します。


以下のページを参考にさせていただきました。ありがとうございます。
http://www.softist.com/programming/listctrl-edit/listctrl-edit.htm
http://www.usamimi.info/~mikanplus/windows/subedit_list2.htm



##前置き
以下の前提条件で進めます。

ソリューション名：ListCtrlTest001
プロジェクトの種類：MFCアプリケーション
アプリケーションの種類：ダイアログベース

ツールボックスからListControlを追加
ID：IDC_LIST1
View:レポートへ変更



##編集用CEdit派生クラス作成
1.プロジェクト→クラスの追加より以下のクラスを追加。
クラス名：MyInputEdit
基底クラス：CEdit

2.IDC_SUB_ITEM,CHANGE_LIST1,KILL_FORCUS,とint Itemとint SubItem;を追加。
SendMessageでリターンキーが押されたこと、フォーカスを失ったことを伝えるメッセージとCListCtrlのインデックス・サブインデックス保存用のメンバ変数を追加。
テスト用なのでpublicにメンバ変数。

```MyInputEdit.h

//この3個を追加
#define IDC_SUB_ITEM WM_APP+1
#define CHANGE_LIST1 WM_APP+2
#define KILL_FORCUS WM_APP+3

class MyInputEdit : public CEdit
{
	DECLARE_DYNAMIC(MyInputEdit)

public:
	MyInputEdit();
	virtual ~MyInputEdit();

    //このメンバ変数を追加
	int Item;
	int SubItem;
/***以下略***/

```


3.ハンドラーを2個追加
OnEnKillfocus(),OnGetDlgCode()
以下のように追記

```MyInputEdit.cpp

void MyInputEdit::OnEnKillfocus()
{
	// フォーカスを失うと確定＋CEditをdelete
	CString *inputtext;
	inputtext = new CString();
	GetWindowText(*inputtext);
	
	CPoint *point;
	point = new CPoint();
	point->x = Item;
	point->y = SubItem;

	WPARAM w = (WPARAM) point;
	LPARAM l = (LPARAM) inputtext;

	AfxGetMainWnd()->SendMessage(CHANGE_LIST1, w, l);
	AfxGetMainWnd()->SendMessage(KILL_FORCUS, 0, 0);

	delete point;
	delete inputtext;
}

UINT MyInputEdit::OnGetDlgCode()
{
	//リターンキーを押すと確定
	UINT result = __super::OnGetDlgCode();
	const MSG* msg = CWnd::GetCurrentMessage();
	msg = (LPMSG)msg->lParam;
	if (msg && msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN)
	{
		CString *inputtext;
		inputtext = new CString();
		GetWindowText(*inputtext);

		CPoint *point;
		point = new CPoint();
		point->x = Item;
		point->y = SubItem;

		WPARAM w = (WPARAM)point;
		LPARAM l = (LPARAM)inputtext;

		AfxGetMainWnd()->SendMessage(CHANGE_LIST1, w, l);

		delete point;
		delete inputtext;
	}
	return CEdit::OnGetDlgCode();
}

```


##ListCtrlTest001.hへコード追加
1.さっき作ったMyInputEdit.hをインクルードしてポインターを追加。
2.メッセージ割り当て関数も追加

```ListCtrlTest001Dlg.h

#include "MyInputEdit.h"
#include "afxcmn.h"

// CListCtrlTest001Dlg ダイアログ
class CListCtrlTest001Dlg : public CDialogEx
{
	//以下のポインタを追加
	MyInputEdit *edit;
	CString *text;
	CPoint *point;

/***以下中略***/

	//CEditのリターンによる更新とフォーカス関連の追加
	afx_msg long ChangeList1(WPARAM, LPARAM);
	afx_msg long KillForcus(WPARAM, LPARAM);
};

```

##ListCtrlTest001.cppへコード追加
1.IDC_LIST1のイベントハンドラOnNMDblclkList1を追加
2.IDC_LIST1へは今回グローバル変数を使用してアクセス。
3.IDC_LIST1のスタイルはLVS_EX_GRIDLINESとLVS_EX_FULLROWSELECT
textとpointは適当な場所でdelete（今回は記述無し Detected memory leaks!と怒られます）
ONOK()はコメントアウトで対応

```ListCtrlTest001Dlg.h

CListCtrl* List1;
BOOL CListCtrlTest001Dlg::OnInitDialog()
{
/***前略***/
	List1 = (CListCtrl*)GetDlgItem(IDC_LIST1);

	//ダミー文字列
	List1->InsertColumn(0, _T("00"), 0, 100, -1);
	List1->InsertColumn(1, _T("11"), 0, 100, -1);
	List1->InsertColumn(2, _T("22"), 0, 100, -1);
	List1->InsertItem(0, _T("0"));
	List1->InsertItem(1, _T("1"));
	List1->InsertItem(2, _T("2"));

	List1->SetExtendedStyle(LVS_EX_GRIDLINES|LVS_EX_FULLROWSELECT);
	text = new CString();
	point = new CPoint();

	edit = NULL;
	return TRUE;  
}

void CListCtrlTest001Dlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: ここにコントロール通知ハンドラー コードを追加します。
	*pResult = 0;

	CString txt;
	UpdateData(TRUE);

	int item = pNMItemActivate->iItem;
	int sub = pNMItemActivate->iSubItem;

	if (sub <= 0 || item < 0)
		return;

	txt.Format(_T("%d,%d"), item, sub);

	CRect cellrect;
	List1->GetSubItemRect(item, sub, LVIR_BOUNDS, cellrect);

	edit = new MyInputEdit();
	edit->Create(WS_VISIBLE | WS_TABSTOP | ES_AUTOHSCROLL | WS_BORDER, cellrect, List1, IDC_SUB_ITEM);
	CFont *font = List1->GetFont();
	edit->SetFont(font);
	edit->Item = item;
	edit->SubItem = sub;
	edit->SetWindowText(List1->GetItemText(item, sub));
	edit->SetFocus();
}

long CListCtrlTest001Dlg::ChangeList1(WPARAM p, LPARAM l)
{
	point = (CPoint *)p;
	text = (CString *)l;

	List1->SetItemText(point->x, point->y, *text);

	return 0;
}

long CListCtrlTest001Dlg::KillForcus(WPARAM, LPARAM)
{
	delete edit;
	edit = NULL;

	return 0;
}

```

とりあえず、これで動くはず？