今更ながら、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にメンバ変数。
//この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()
以下のように追記
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.メッセージ割り当て関数も追加
#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()はコメントアウトで対応
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;
}
とりあえず、これで動くはず?