본문 바로가기
개발/mfc

mfc, List Control Cell값 수정 edit, 변경 하기 - sample source

by 즐기며 2024. 11. 15.

win 11, visual studio 2010 에서 했읍니다.

 

mfc 에서 제공 되는 List control 은 수정 이 안된다.

지금 소개 하는 방법은 편법 이다.

List control 의 한 Cell 을 선택 하면 Edit control 을 선택하고, 그 값을 수정 하게 하여 다시 list 에 저장하는 방법 이다.

구차 하게,,  

 

다 만들면 이용 방법은

list cell DOUBLE CLICK -> EDIT -> [Enter]

또는 

list cell one CLICK ->  [F2] -> EDIT -> [Enter]

이다.

즉 둘다 되는데, 사실 더블클릭만 쓰는게 편하니 이거만 해도 된다.
 

 

실행 창 입니다.

 

어째든 간단히 한다고 하는데, 나름 동작은 그럴싸 합니다.

 

순서.

1. list 와 edit 를 만든다.

- List member 변수 : m_Lst_mac

- Edit ID : IDC_m_ED_forList

 

 

2. 추가로 위치 변수 만든다

- int iSavedItem, iSavedSubitem;

- 그로발 하게 써야 하므로, class 의 멤버 변수로 하든, 그로발 변수로 하든 2개 만든다.

 

 

3. OnInitDialog에서 샘플 데이터를 넣어놓고, 1번에서 만든 에디트 컨트롤을 숨긴다

int iSavedItem, iSavedSubitem;

void CDlg_Main::addLine2List( CListCtrl *pLc, CString s )
{
	CString cS;
	int nL = pLc->GetItemCount();
	cS.Format(_T("%d"), nL+1);
	pLc->InsertItem(nL, cS );		// 한 줄 추가 하며 첫 column (0) 에 번호 입력
	pLc->SetItem(nL, 1, LVIF_TEXT, s, NULL, NULL, NULL, NULL); // 두번째 column 에 문자추가
} // addLine2List()

void CDlg_Main::initList( CListCtrl *pLc )
{
	int //nL,		// 줄번호
		cx;		// 넓이
	CRect rt;     // 리스트 컨트롤의 크기를 가져올 변수

	pLc->GetWindowRect(&rt);
	cx = rt.right - rt.left;  // 넓이 계산

	pLc->SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);   // 리스트 컨트롤에 선표시 및 Item 선택시 한행 전체 선택
//	pLc->SetExtendedStyle(LVS_EX_CHECKBOXES);  // Check Box
	pLc->ModifyStyle(0, LVS_SHOWSELALWAYS);		// 포커스를 잃어도 선택된 아이템 유지하는 옵션, 파랑으로 안보이고 아쉽게 회색으로 보이는군

	pLc->InsertColumn(1, TEXT("#"), LVCFMT_CENTER, 50 );     // 첫번째  LVCFMT_LEFT, LVCFMT_CENTER, LVCFMT_RIGHT
	pLc->InsertColumn(2, _T("Macro"), LVCFMT_LEFT, 1000);   // 세번째

	pLc->DeleteAllItems();
	addLine2List(pLc, _T("\"123\""));
	addLine2List(pLc, _T("'123'"));
	addLine2List(pLc, _T("\"1234\"'5678'"));

	ListSelectLine( pLc, 0);	// 첫줄에
}


BOOL CDlg_Main::OnInitDialog()
{
..
	initList( &m_Lst_mac );	//  List 초기화
    GetDlgItem(IDC_m_ED_forList)->SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW ); // 구석테기에 짱박히게
..
}

 

4. List 에서 event  3가지 추가

- List 선택 > Properties 선택 > Event 선택

- NM_CLICK, NM_DBLCLK, LVN_KEYDOWN  를 추가한다

 

 

 

- 추가 할때 자동으로 생긴 소스 , 그냥 참고 하셔요

// Event 추가 하면 자동으로 만들어 지는 코드들,

// ~.h
public:
	afx_msg void OnNMClickmList(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnNMDblclkmList(NMHDR *pNMHDR, LRESULT *pResult);
	afx_msg void OnLvnKeydownmList(NMHDR *pNMHDR, LRESULT *pResult);


// ~.cpp
BEGIN_MESSAGE_MAP(CDlg_Main, CDialogEx)
	ON_NOTIFY(NM_CLICK, IDC_m_LIST, &CDlg_Main::OnNMClickmList)
	ON_NOTIFY(NM_DBLCLK, IDC_m_LIST, &CDlg_Main::OnNMDblclkmList)
	ON_NOTIFY(LVN_KEYDOWN, IDC_m_LIST, &CDlg_Main::OnLvnKeydownmList)
END_MESSAGE_MAP()

void CDlg_Main::OnNMClickmList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
}

void CDlg_Main::OnNMDblclkmList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
}

void CDlg_Main::OnLvnKeydownmList(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
}

 

 

5. 추가된 소스에서 3가지 함수를 수정 한다

 

- 더블클릭시에   
1) 클릭한 위치가 리스트컨트롤에서 유효한 행, 열이면 에디트 박스를 위치시킨다  
2) subitem의 위치가 0번이면 따로 계산을 한다(전체행을 가리키는 위치가 나오므로) 

// 더블클릭시에   
// 1) 클릭한 위치가 리스트컨트롤에서 유효한 행, 열이면 에디트 박스를 위치시킨다  
// 2) subitem의 위치가 0번이면 따로 계산을 한다(전체행을 가리키는 위치가 나오므로) 
void CDlg_Main::OnNMDblclkmList(NMHDR *pNMHDR, LRESULT *pResult)  // 
{
//	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	LPNMITEMACTIVATE pNMITEM =(LPNMITEMACTIVATE) pNMHDR;
	iSavedItem = pNMITEM->iItem;
	iSavedSubitem = pNMITEM->iSubItem;
	if( pNMITEM->iItem != -1 ) {
		CRect rect;
		if( pNMITEM->iSubItem == 0 ) {
			m_Lst_mac.GetItemRect( pNMITEM->iItem, rect, LVIR_BOUNDS);
			rect.right = rect.left + m_Lst_mac.GetColumnWidth(0);
		} else {
			m_Lst_mac.GetSubItemRect( pNMITEM->iItem, pNMITEM->iSubItem, LVIR_BOUNDS, rect);
		}
		m_Lst_mac.ClientToScreen(rect);
		this->ScreenToClient(rect);
		GetDlgItem(IDC_m_ED_forList)->SetWindowText(m_Lst_mac.GetItemText(  pNMITEM->iItem, pNMITEM->iSubItem ));
		GetDlgItem(IDC_m_ED_forList)->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW);
		GetDlgItem(IDC_m_ED_forList)->SetFocus();
	}
	*pResult = 0;
}

 

이거 하나로 일단 "더블클릭- 수정- 엔터" 로 동작 하지만(물론 ENTER 동작은 추가해야), 다음 2개 더해 보자. 

 

- 클릭시는 위치만 기억 한다.

void CDlg_Main::OnNMClickmList(NMHDR *pNMHDR, LRESULT *pResult) // 클릭시에는 위치만 기억
{
//	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	LPNMITEMACTIVATE pNMITEM =(LPNMITEMACTIVATE) pNMHDR;
	iSavedItem= iSavedSubitem= -1;
	GetDlgItem(IDC_m_ED_forList)->SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW );
	if( pNMITEM->iItem != 1 ) {
		iSavedItem = pNMITEM->iItem;
		iSavedSubitem = pNMITEM->iSubItem;
	}
	*pResult = 0;
}

 


-  F2키를 누르면, 마지막에 선택되었던 위치의 행, 열 값을 Edit에 복사하여 수정 가능 하게한다

void CDlg_Main::OnLvnKeydownmList(NMHDR *pNMHDR, LRESULT *pResult)  // F2키를 누르면, 마지막에 선택되었던 위치의 행, 열 값을 수정한다
{
	LPNMLVKEYDOWN pLVKeyDow = reinterpret_cast<LPNMLVKEYDOWN>(pNMHDR);
	// TODO: Add your control notification handler code here
	if( pLVKeyDow->wVKey == VK_F2 ) {
		if( iSavedItem != -1 ) {
			CRect rect;
			if( iSavedSubitem == 0 ) {
				m_Lst_mac.GetItemRect( iSavedItem, rect, LVIR_BOUNDS);
				rect.right = rect.left + m_Lst_mac.GetColumnWidth(0);
			} else {
				m_Lst_mac.GetSubItemRect(  iSavedItem, iSavedSubitem, LVIR_BOUNDS, rect);
			}
			m_Lst_mac.ClientToScreen(rect);
			this->ScreenToClient(rect);
			GetDlgItem(IDC_m_ED_forList)->SetWindowText(m_Lst_mac.GetItemText(  iSavedItem, iSavedSubitem ));
			GetDlgItem(IDC_m_ED_forList)->SetWindowPos(NULL, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_SHOWWINDOW);
			GetDlgItem(IDC_m_ED_forList)->SetFocus();
		}
	}
	*pResult = 0;
}

 

6. Edit box 에서 수정 된것을 List control 로 옮기기.

- 에디트박스에서 엔터키를 누르면, 리스트컨트롤에 값을 적용한다

BOOL CDlg_Main::PreTranslateMessage(MSG* pMsg) { // Enter, ESC key 안먹게,
	CString cS;
	if (pMsg->message == WM_KEYDOWN)
	{
		if(pMsg->wParam == VK_RETURN) {
			// 에디트박스에서 엔터키를 누르면, 리스트컨트롤에 값을 적용
			if ( pMsg->hwnd == GetDlgItem(IDC_m_ED_forList)->GetSafeHwnd()){
				GetDlgItemText(IDC_m_ED_forList, cS);
				m_Lst_mac.SetItemText(iSavedItem, iSavedSubitem, cS);
				GetDlgItem(IDC_m_ED_forList)->SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW );
			}
			return TRUE;
		}
		if (pMsg->wParam == VK_ESCAPE )	return TRUE;
	}

	return CDialogEx::PreTranslateMessage(pMsg);
}

 

우와, 나름 간단 하면서 동작 잘 하네요...

 

 

수고 하셨읍니다.

 

고맙읍니다.

'개발 > mfc' 카테고리의 다른 글

mfc, 일반 Class 추가 하기  (0) 2024.12.16
mfc, Visual Studio project 명, 이름 변경하기  (1) 2024.11.18
mfc, Enter, ESC 등 입력 키 감지  (0) 2024.11.14
mfc, Project 만들기  (0) 2024.10.31
mfc, combobox 만들기, 고치기  (0) 2024.10.29