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 |