LoginSignup
2
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-10-17

今更ながら、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;
}

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

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4