I have a CListCtrl where I display a textbox over a cell to allow the user to edit the cell's text.
This works, but I don't think the textbox will stay at the right location for different UI styles, based on user windows settings.
Does anyone know of a reliable way to center the textbox window over the cell the user clicked? Here is the code I am using now. I am not concerned about the right side of the textbox where I add the value 16. I only want a reliable way to get where to put the left and top of the textbox.
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;
}
Thanks.
It depends how editText
was created. If the parent of editText
is the ListView control, for example:
editText.Create(WS_CHILD, CRect(0, 0, 1, 1), &filesList, 1);
Then there is no need to adjust anything, simply use rectItem
as is:
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;
}
If on the other hand editText
's parent is not the ListView control, then the editbox will not position itself relative to ListView, therefore its position must be adjusted.
For example if editText
was initialized in DoDataExchange
then offset rectItem
as follows:
POINT p = { 0 };
filesList.MapWindowPoints(this, &p, 1);
rectItem.OffsetRect(p.x, p.y);
...
editText.MoveWindow(rectItem, 1);