MFC CListCtrl 在单元格上显示文本框供用户编辑
MFC CListCtrl displaying a textbox over a cell for user edit
我有一个 CListCtrl,我在单元格上方显示一个文本框,以允许用户编辑单元格的文本。
这行得通,但我认为文本框不会根据用户 windows 设置针对不同的 UI 样式停留在正确的位置。
有谁知道将文本框 window 置于用户单击的单元格上方的可靠方法?这是我现在使用的代码。我不关心我添加值 16 的文本框右侧。我只想要一种可靠的方法来获取放置文本框左侧和顶部的位置。
void FilesDialog::OnNMClickFiles(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE)pNMHDR;
//get the row number
nItem = temp->iItem;
//get the column number
nSubItem = temp->iSubItem;
if (nSubItem == 0 || nSubItem == -1 || nItem == -1)
{
*pResult = 0;
return;
}
//Retrieve the text of the selected subItem from the list
CString str = GetItemText(filesList.m_hWnd, nItem, nSubItem);
CRect rectList, rectDlg, rectCl;
CRect rectItem;
// Get the rectangle of the selected sub-item.
ListView_GetSubItemRect(filesList.m_hWnd, temp->iItem, temp->iSubItem, LVIR_BOUNDS, &rectItem);
//Get the Rectange of the listControl
::GetWindowRect(temp->hdr.hwndFrom, &rectList);
//Get the Rectange of the Dialog
::GetWindowRect(this->m_hWnd, &rectDlg);
GetClientRect(&rectCl);
//this->ScreenToClient(&rectCl);
int subY = rectDlg.Height() - rectCl.Height() - 5;
int lft = rectItem.left + rectList.left - rectDlg.left + 1;
int tp = rectItem.top + rectList.top - rectDlg.top - subY;
// When an item is cut off by the window on the right
// side, resize the text box so that the right side
// is at the edge of the list control.
int rtEdge = rectDlg.right - (rectDlg.right - rectCl.right);
int subWdth = 0;
if (lft + rectItem.Width() - 2 > rtEdge)
{
// 16 is just an arbitrary value that seems to work.
subWdth = 16 + (lft + rectItem.Width() - 2) - rtEdge;
}
// Move the edit box window over the cell.
editText.MoveWindow(lft, tp, rectItem.Width() - 2 - subWdth, rectItem.Height() - 1, true);
//Set the list Item text in the edit box.
::SetWindowText(editText.m_hWnd, str);
// Show the edit box and set focus to it.
::ShowWindow(editText.m_hWnd, SW_SHOW);
::SetFocus(editText.m_hWnd);
*pResult = 0;
}
谢谢。
这取决于 editText
的创建方式。如果editText
的父控件是ListView控件,例如:
editText.Create(WS_CHILD, CRect(0, 0, 1, 1), &filesList, 1);
那就不用调整了,直接用rectItem
就可以了:
void FilesDialog::OnNMClickFiles(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE)pNMHDR;
if (temp->iSubItem == 0 || temp->iSubItem == -1 || temp->iItem == -1)
{
*pResult = 0;
return;
}
CString str = filesList.GetItemText(temp->iItem, temp->iSubItem);
CRect rectItem;
filesList.GetSubItemRect(temp->iItem, temp->iSubItem, LVIR_BOUNDS, rectItem);
editText.SetWindowText(str);
editText.MoveWindow(rectItem, 1);
editText.ShowWindow(SW_SHOW);
*pResult = 0;
}
如果 editText
的父控件不是 ListView 控件,则编辑框将不会相对于 ListView 定位,因此必须调整其位置。
例如,如果 editText
在 DoDataExchange
中初始化,则偏移 rectItem
如下:
POINT p = { 0 };
filesList.MapWindowPoints(this, &p, 1);
rectItem.OffsetRect(p.x, p.y);
...
editText.MoveWindow(rectItem, 1);
我有一个 CListCtrl,我在单元格上方显示一个文本框,以允许用户编辑单元格的文本。
这行得通,但我认为文本框不会根据用户 windows 设置针对不同的 UI 样式停留在正确的位置。
有谁知道将文本框 window 置于用户单击的单元格上方的可靠方法?这是我现在使用的代码。我不关心我添加值 16 的文本框右侧。我只想要一种可靠的方法来获取放置文本框左侧和顶部的位置。
void FilesDialog::OnNMClickFiles(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE)pNMHDR;
//get the row number
nItem = temp->iItem;
//get the column number
nSubItem = temp->iSubItem;
if (nSubItem == 0 || nSubItem == -1 || nItem == -1)
{
*pResult = 0;
return;
}
//Retrieve the text of the selected subItem from the list
CString str = GetItemText(filesList.m_hWnd, nItem, nSubItem);
CRect rectList, rectDlg, rectCl;
CRect rectItem;
// Get the rectangle of the selected sub-item.
ListView_GetSubItemRect(filesList.m_hWnd, temp->iItem, temp->iSubItem, LVIR_BOUNDS, &rectItem);
//Get the Rectange of the listControl
::GetWindowRect(temp->hdr.hwndFrom, &rectList);
//Get the Rectange of the Dialog
::GetWindowRect(this->m_hWnd, &rectDlg);
GetClientRect(&rectCl);
//this->ScreenToClient(&rectCl);
int subY = rectDlg.Height() - rectCl.Height() - 5;
int lft = rectItem.left + rectList.left - rectDlg.left + 1;
int tp = rectItem.top + rectList.top - rectDlg.top - subY;
// When an item is cut off by the window on the right
// side, resize the text box so that the right side
// is at the edge of the list control.
int rtEdge = rectDlg.right - (rectDlg.right - rectCl.right);
int subWdth = 0;
if (lft + rectItem.Width() - 2 > rtEdge)
{
// 16 is just an arbitrary value that seems to work.
subWdth = 16 + (lft + rectItem.Width() - 2) - rtEdge;
}
// Move the edit box window over the cell.
editText.MoveWindow(lft, tp, rectItem.Width() - 2 - subWdth, rectItem.Height() - 1, true);
//Set the list Item text in the edit box.
::SetWindowText(editText.m_hWnd, str);
// Show the edit box and set focus to it.
::ShowWindow(editText.m_hWnd, SW_SHOW);
::SetFocus(editText.m_hWnd);
*pResult = 0;
}
谢谢。
这取决于 editText
的创建方式。如果editText
的父控件是ListView控件,例如:
editText.Create(WS_CHILD, CRect(0, 0, 1, 1), &filesList, 1);
那就不用调整了,直接用rectItem
就可以了:
void FilesDialog::OnNMClickFiles(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMITEMACTIVATE temp = (LPNMITEMACTIVATE)pNMHDR;
if (temp->iSubItem == 0 || temp->iSubItem == -1 || temp->iItem == -1)
{
*pResult = 0;
return;
}
CString str = filesList.GetItemText(temp->iItem, temp->iSubItem);
CRect rectItem;
filesList.GetSubItemRect(temp->iItem, temp->iSubItem, LVIR_BOUNDS, rectItem);
editText.SetWindowText(str);
editText.MoveWindow(rectItem, 1);
editText.ShowWindow(SW_SHOW);
*pResult = 0;
}
如果 editText
的父控件不是 ListView 控件,则编辑框将不会相对于 ListView 定位,因此必须调整其位置。
例如,如果 editText
在 DoDataExchange
中初始化,则偏移 rectItem
如下:
POINT p = { 0 };
filesList.MapWindowPoints(this, &p, 1);
rectItem.OffsetRect(p.x, p.y);
...
editText.MoveWindow(rectItem, 1);