现在我的CListCtrl单元格是可以编辑的,我如何才能实现,比如现在编辑的是第一行第一列的单元格,按下回车后自动定位到第二行第一列继续编辑?
以下代码是我实现单元格可编辑的代码
void CListctrledit::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
//进行单击检测,这个结构已经被扩展为能够适应子项的单击检测。
LVHITTESTINFO cHitTest;
cHitTest.pt = pNMItemActivate->ptAction;
if (-1 != SubItemHitTest(&cHitTest)) //检测位于哪个单元格上
{
if (cHitTest.flags & LVHT_ONITEMLABEL)
{
m_iCurRow = cHitTest.iItem;
m_iCurColunm = cHitTest.iSubItem;
if (pNMItemActivate->iSubItem != 0)
{
//获取单元格信息
CRect rect; //单元格的尺寸
GetSubItemRect(m_iCurRow, m_iCurColunm, LVIR_LABEL, rect); //这个坐标是相对于ListCtrl左上角的
CString sValue = GetItemText(m_iCurRow, m_iCurColunm); //获取当前单元格的内容
//创建编辑框
if (!m_wndEdt.m_hWnd)
{
m_wndEdt.Create(WS_CHILD | ES_CENTER | ES_AUTOHSCROLL | ES_WANTRETURN | ES_MULTILINE, rect, this, 1);
m_wndEdt.SetFont(this->GetFont(), FALSE); //设置编辑框的字体
}
//使编辑框文本水平居中
CRect rcEdit;
GetDlgItem(1)->GetClientRect(&rcEdit);
::OffsetRect(&rcEdit, 0, 2); //后两个参数代表横向,纵向偏移
::SendMessageA(((CComboBox*)GetDlgItem(1))->m_hWnd, EM_SETRECT, 0, (LPARAM)&rcEdit);
rect.left = 100;
m_wndEdt.SetWindowText(sValue);
m_wndEdt.MoveWindow(rect);
m_wndEdt.ShowWindow(SW_SHOW);
m_wndEdt.CreateSolidCaret(1, rect.Height() - 5);//创建一个光标
//m_wndEdt.ShowCaret();//显示光标
//m_wndEdt.SetSel(-1);//使光标移到最后面
int iLength = sValue.GetLength();
m_wndEdt.SetSel(0, iLength, FALSE);//设置光标选中所有文字
m_wndEdt.SetFocus();
}
}
*pResult = 0;
}
}
//获取修改后的值
void CListctrledit::OnEnEdtKillFocus()
{
m_wndEdt.ShowWindow(SW_HIDE);
if (m_iCurColunm < 0 || m_iCurRow < 0)
return;
CString sEdt;
m_wndEdt.GetWindowText(sEdt);
SetItemText(m_iCurRow, m_iCurColunm, sEdt); //更新List Control的单元格显示
m_wndEdt.ShowWindow(SW_HIDE);//隐藏编辑框
}
// 声明消息映射
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
ON_NOTIFY(LVN_ENDLABELEDIT, IDC_LIST_CTRL, OnEndLabelEdit)
END_MESSAGE_MAP()
// 处理LVN_ENDLABELEDIT消息
void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem = &(pDispInfo)->item;
// 获取当前编辑的单元格的行和列索引
int row = pItem->iItem;
int col = pItem->iSubItem;
// 设置焦点到下一个单元格
SetItemState(row + 1, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
EnsureVisible(row + 1, FALSE);
EditLabel(row + 1);
*pResult = 0;
}
要实现这个功能,您可以在 CListCtrl 的 OnKeyDown() 函数中处理按键事件,并使用 SetItemState() 函数将焦点转移到下一个单元格。例如:
void MyListCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_RETURN) // 如果用户按下回车键
{
int row = GetNextItem(-1, LVNI_FOCUSED); // 获取当前选中行
int col = GetNextItem(-1, LVNI_FOCUSED | LVNI_COLUMN); // 获取当前选中列
SetItemState(row, col, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
// 将焦点移到下一个单元格
col++;
if (col >= GetHeaderCtrl()->GetItemCount()) // 如果已到达最后一列,则跳到下一行
{
col = 0;
row++;
}
if (row >= GetItemCount()) // 如果已到达最后一行,则回到第一行
{
row = 0;
}
EnsureVisible(row, TRUE);
EditLabel(row, col);
}
else
{
CListCtrl::OnKeyDown(nChar, nRepCnt, nFlags);
}
}
在这个示例中,我们首先获取当前选中的单元格的行和列。然后我们使用 SetItemState() 函数将选中状态设置为当前单元格。接下来,我们将焦点移到下一个单元格,如果已经到达最后一列,则移到下一行。最后,我们调用 EditLabel() 函数打开当前单元格的编辑框。
这个修改的多处代码,你的代码也没上全,所以不能发完整代码出来。需要处理的是编辑框的回车事件,在其中首先结束编辑,然后移到下一行编辑。这是部分实现可以参考一下:
BOOL CListctrledit::PreTranslateMessage(MSG* pMsg)
{
// TODO: 在此添加专用代码和/或调用基类
if (WM_KEYDOWN == pMsg->message && VK_RETURN == pMsg->wParam)
{
if (GetFocus() == GetDlgItem(1)) //根据不同控件焦点判断是那个在执行
{
//MessageBox(_T("Enter Catched!"));
OnEnEdtKillFocus();
m_iCurRow++;
EditContent();//这个需要重写
}
return true;
}
return CListCtrl::PreTranslateMessage(pMsg);
}