相信很多人用過MFC的新手都知道,MFC雖然封裝了一些常用的控件,但不少控件真正使用起來,與個人的要求可能會有一些差别,總有一些功能不是很友善就能實作的,例如CTabCtrl(Tab控件)的顔色(涉及到自繪、頭大)/CListCtrl的子項編輯。 報表風格的清單控件,在資源裡設定了“可就地編輯”的屬性,子項雖然能夠編輯,但編輯框是出現在第一列的,即不管你選擇修改的項是在第幾列,編輯框總是出現在相應行的第一列位置,很麻煩,而且經過我的嘗試,編輯完後的文本儲存,也是需要自己實作的。
為了簡便實作,我沒有派生子類,而是在資源中添加一個編輯框,通過将編輯框顯示隐藏在指定位置,達到可編輯的目的,在編輯框失去焦點時,将文本顯示在ListCtrl中。
下面是我的實作方法:
1. 資源裡拖入一個CEdit Box控件,關聯control變量m_SubItemEdit,關聯value變量CString m_strEditText,在對話框初始化函數OnInitDialog()裡将編輯框隐藏起來: m_SubItemEdit.ShowWindow(SW_HIDE);
2. 在對話框上拖入一個CListCtrl清單控件,設定後屬性,風格(報表-report),添加變量m_ListCtrl,在對話框初始化函數裡加入清單控件的一些初始化操作,
在 OninitDialog中初始化清單框:
m_ListCtrl.SetExtendedStyle( //設定風格
LVS_EX_FLATSB //扁平風格滾動條
| LVS_EX_FULLROWSELECT //允許整行選中
| LVS_EX_HEADERDRAGDROP //允許标題拖拽
| LVS_EX_ONECLICKACTIVATE //高亮顯示
| LVS_EX_GRIDLINES //畫出網格線
);
m_ListCtrl.InsertColumn(0, _T("姓名"), LVCFMT_LEFT, 150, 0);
m_ListCtrl.InsertColumn(1, _T("聯系電話"), LVCFMT_LEFT, 150, 1);
m_ListCtrl.InsertItem(0, _T(""));
m_ListCtrl.SetItemText(0, 0, _T("周芷若"));
m_ListCtrl.SetItemText(0, 1, _T("123456789"));
m_ListCtrl.InsertItem(1, _T(""));
m_ListCtrl.SetItemText(1, 0, _T("張無忌"));
m_ListCtrl.SetItemText(1, 1, _T("987654321"));
m_SubItemEdit.ShowWindow(SW_HIDE);
3. 響應CListCtrl控件的NM_DBLCLK(訓示使用者在控件内輕按兩下了滑鼠左鍵),以下是響應函數的處理,實作子項的可編輯化。
void CEditListCtrlDlg::OnNMDblclkList1(NMHDR *pNMHDR, LRESULT *pResult)
{
//LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
// TODO: 在此添加控件通知處理程式代碼
//*pResult = 0;
NM_LISTVIEW *pNMListCtrl = (NM_LISTVIEW *)pNMHDR;
if (pNMListCtrl->iItem != -1)
{
CRect rect, dlgRect;
//獲得目前列的寬度以适應如果使用者調整寬度
//此處不用獲得的子項rect矩形框來設定寬度
//是因第一列時傳回的寬度是整行的寬度,我也不知道為啥
int width = m_ListCtrl.GetColumnWidth(pNMListCtrl->iSubItem);
m_ListCtrl.GetSubItemRect(pNMListCtrl->iItem, pNMListCtrl->iSubItem, LVIR_BOUNDS, rect);
//是以需要儲存清單的索引
//以及子項相對應的行列号索引
listSelItem[0] = pNMListCtrl->iItem;
listSelItem[1] = pNMListCtrl->iSubItem;
//獲得listctrl矩形框
//獲得父對話框的位置以調整CEdit的顯示位置,具體見下面代碼
m_ListCtrl.GetWindowRect(&dlgRect);
ScreenToClient(&dlgRect);
int height = rect.Height();
rect.top += (dlgRect.top + 1);
rect.left += (dlgRect.left + 1);
rect.bottom = rect.top + height + 2;
rect.right = rect.left + width + 2;
m_SubItemEdit.MoveWindow(&rect);
m_SubItemEdit.ShowWindow(SW_SHOW);
m_SubItemEdit.SetFocus();
}
}
4.到了這裡,應該就可以實作輕按兩下編輯控件了,但隻是編輯而已,沒有實作儲存,要實作儲存,還得對CEDIT失去焦點消息進行相應,以下是響應函數,因為我還做了CEdit控件對于Enter鍵實作儲存編輯的功能
void CEditListCtrlDlg::SetListItemText(void)
{
UpdateData(TRUE);
//此處的cstrItemTextEdit是CEdit控件的字元串關聯變量
m_ListCtrl.SetItemText(listSelItem[0], listSelItem[1], m_strEditText);
//重置編輯框文本
m_SubItemEdit.SetWindowText(_T(""));
//隐藏編輯框
m_SubItemEdit.ShowWindow(SW_HIDE);
//強制重新整理清單控件(否則視覺上有感覺有點不爽,可以試試^_^)
m_ListCtrl.Invalidate();
}
5. 響應CEdit控件的EN_KILLFOCUS函數
void CEditListCtrlDlg::OnEnKillfocusEdit1()
{
// TODO: 在此添加控件通知處理程式代碼
SetListItemText();
}
6.處理Enter鍵的響應,是以直接重載對話框的PreTranslateMessage函數,然後在函數裡做處理
BOOL CEditListCtrlDlg::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加專用代碼和/或調用基類
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
{
if (GetFocus()->GetDlgCtrlID() == IDC_EDIT1)
{
//使清單控件獲得焦點,則CEdit會自動失去焦點,觸發EN_KILLFOCUS消息
m_ListCtrl.SetFocus();
}
return TRUE;
}
return CDialogEx::PreTranslateMessage(pMsg);
}