to lzmailcn: subitem 也是可以编辑的。post 一篇codeguru上的文章,希望对你有帮助。 -------------------------------------------------------------------------------- The default implementation of the ListView control allows editing of the first column label only. You have to create your own edit control to allow editing of subitems. Step 1: Derive a class from CListCtrl In the code below, CMyListCtrl is the name used for the derived class. You can also derive a class from CListView if you need this functionality in a CView rather than in a control. If you are already working with a sub-class of CListCtrl, you can make the modifications to that class. Step 2: Define HitTestEx() Define an extended HitTest function for the CMyListCtrl class. This function will determine the row index that the point falls over and also determine the column. The HitTestEx() has already been listed and explained in an earlier section and is listed here again for completeness. We need this function if the user interface to initiate the edit is a mouse click or a double click. See the section "Detecting column index of the item clicked". // HitTestEx - Determine the row index and column index for a point // Returns - the row index or -1 if point is not over a row // point - point to be tested. // col - to hold the column index int CMyListCtrl::HitTestEx(CPoint &point, int *col) const { int colnum = 0; int row = HitTest( point, NULL );
if( col ) *col = 0; // Make sure that the ListView is in LVS_REPORT if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT ) return row; // Get the top and bottom row visible row = GetTopIndex(); int bottom = row + GetCountPerPage(); if( bottom > GetItemCount() ) bottom = GetItemCount();
// Get the number of columns CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); int nColumnCount = pHeader->GetItemCount(); // Loop through the visible rows for( ;row <=bottom;row++) { // Get bounding rect of item and check whether point falls in it. CRect rect; GetItemRect( row, &rect, LVIR_BOUNDS ); if( rect.PtInRect(point) ) { // Now find the column for( colnum = 0; colnum < nColumnCount; colnum++ ) { int colwidth = GetColumnWidth(colnum); if( point.x >= rect.left && point.x <= (rect.left + colwidth ) ) { if( col ) *col = colnum; return row; } rect.left += colwidth; } } } return -1; }
Step 3: Add function to initiate the edit The user interface to initiate an edit for a sub item may be click on an already selected row, a double click or even a push button. We define a helper function to set up the edit control. The helper function takes only the row and column index of the subitem. EditSubLabel() ensures that the row as well as the column is visible before it creates the edit control. It then creates the edit control of the right size and with the proper text justification. The edit control created is of the class CInPlaceEdit which we will define later. // EditSubLabel - Start edit of a sub item label // Returns - Temporary pointer to the new edit control // nItem - The row index of the item to edit // nCol - The column of the sub item. CEdit* CMyListCtrl::EditSubLabel( int nItem, int nCol ) { // The returned pointer should not be saved // Make sure that the item is visible if( !EnsureVisible( nItem, TRUE ) ) return NULL; // Make sure that nCol is valid CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0); int nColumnCount = pHeader->GetItemCount(); if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 ) return NULL; // Get the column offset int offset = 0; for( int i = 0; i < nCol; i++ ) offset += GetColumnWidth( i ); CRect rect; GetItemRect( nItem, &rect, LVIR_BOUNDS ); // Now scroll if we need to expose the column CRect rcClient; GetClientRect( &rcClient ); if( offset + rect.left < 0 || offset + rect.left > rcClient.right ) { CSize size; size.cx = offset + rect.left; size.cy = 0; Scroll( size ); rect.left -= size.cx; } // Get Column alignment LV_COLUMN lvcol; lvcol.mask = LVCF_FMT; GetColumn( nCol, &lvcol ); DWORD dwStyle ; if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT) dwStyle = ES_LEFT; else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT) dwStyle = ES_RIGHT; else dwStyle = ES_CENTER; rect.left += offset+4; rect.right = rect.left + GetColumnWidth( nCol ) - 3 ; if( rect.right > rcClient.right) rect.right = rcClient.right; dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL; CEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol )); pEdit->Create( dwStyle, rect, this, IDC_IPEDIT ); return pEdit; } Step 4: Handle the scroll messages The CInPlaceEdit class is designed to destroy the edit control and delete the object when it loses focus. Clicking on the scrollbars of the ListView control does not take away the focus from the edit control. We therefore add handlers for the scrollbar messages which force focus away from the edit control by setting the focus to the list view control itself. void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if( GetFocus() != this ) SetFocus(); CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar); }void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { if( GetFocus() != this ) SetFocus(); CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar); } Step 5: Handle EndLabelEdit Like the built in edit control for the first column, our edit control also sends the LVN_ENDLABELEDIT notification when the edit is completed. If this notification message isn’t already being handled, add a handler so that any changes made with the edit control can be accepted. void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR; LV_ITEM *plvItem = &plvDispInfo->item; if (plvItem->pszText != NULL) { SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText); } *pResult = FALSE; }
是VC产生的OnLBtnDblClick的默认处理代码没有注册掉。
谢谢二位。
subitem 也是可以编辑的。post 一篇codeguru上的文章,希望对你有帮助。
--------------------------------------------------------------------------------
The default implementation of the ListView control allows editing of the first column label only. You have to create your own edit control to allow editing of subitems.
Step 1: Derive a class from CListCtrl
In the code below, CMyListCtrl is the name used for the derived class. You can also derive a class from CListView if you need this functionality in a CView rather than in a control. If you are already working with a sub-class of CListCtrl, you can make the modifications to that class.
Step 2: Define HitTestEx()
Define an extended HitTest function for the CMyListCtrl class. This function will determine the row index that the point falls over and also determine the column. The HitTestEx() has already been listed and explained in an earlier section and is listed here again for completeness. We need this function if the user interface to initiate the edit is a mouse click or a double click. See the section "Detecting column index of the item clicked".
// HitTestEx - Determine the row index and column index for a point
// Returns - the row index or -1 if point is not over a row
// point - point to be tested.
// col - to hold the column index
int CMyListCtrl::HitTestEx(CPoint &point, int *col) const
{
int colnum = 0;
int row = HitTest( point, NULL );
if( col ) *col = 0; // Make sure that the ListView is in LVS_REPORT
if( (GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
return row; // Get the top and bottom row visible
row = GetTopIndex();
int bottom = row + GetCountPerPage();
if( bottom > GetItemCount() )
bottom = GetItemCount();
// Get the number of columns
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount(); // Loop through the visible rows
for( ;row <=bottom;row++)
{
// Get bounding rect of item and check whether point falls in it.
CRect rect;
GetItemRect( row, &rect, LVIR_BOUNDS );
if( rect.PtInRect(point) )
{
// Now find the column
for( colnum = 0; colnum < nColumnCount; colnum++ )
{
int colwidth = GetColumnWidth(colnum);
if( point.x >= rect.left
&& point.x <= (rect.left + colwidth ) )
{
if( col ) *col = colnum;
return row;
}
rect.left += colwidth;
}
}
}
return -1;
}
The user interface to initiate an edit for a sub item may be click on an already selected row, a double click or even a push button. We define a helper function to set up the edit control. The helper function takes only the row and column index of the subitem. EditSubLabel() ensures that the row as well as the column is visible before it creates the edit control. It then creates the edit control of the right size and with the proper text justification. The edit control created is of the class CInPlaceEdit which we will define later.
// EditSubLabel - Start edit of a sub item label
// Returns - Temporary pointer to the new edit control
// nItem - The row index of the item to edit
// nCol - The column of the sub item.
CEdit* CMyListCtrl::EditSubLabel( int nItem, int nCol )
{
// The returned pointer should not be saved // Make sure that the item is visible
if( !EnsureVisible( nItem, TRUE ) ) return NULL; // Make sure that nCol is valid
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
if( nCol >= nColumnCount || GetColumnWidth(nCol) < 5 )
return NULL; // Get the column offset
int offset = 0;
for( int i = 0; i < nCol; i++ )
offset += GetColumnWidth( i ); CRect rect;
GetItemRect( nItem, &rect, LVIR_BOUNDS ); // Now scroll if we need to expose the column
CRect rcClient;
GetClientRect( &rcClient );
if( offset + rect.left < 0 || offset + rect.left > rcClient.right )
{
CSize size;
size.cx = offset + rect.left;
size.cy = 0;
Scroll( size );
rect.left -= size.cx;
} // Get Column alignment
LV_COLUMN lvcol;
lvcol.mask = LVCF_FMT;
GetColumn( nCol, &lvcol );
DWORD dwStyle ;
if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_LEFT)
dwStyle = ES_LEFT;
else if((lvcol.fmt&LVCFMT_JUSTIFYMASK) == LVCFMT_RIGHT)
dwStyle = ES_RIGHT;
else dwStyle = ES_CENTER; rect.left += offset+4;
rect.right = rect.left + GetColumnWidth( nCol ) - 3 ;
if( rect.right > rcClient.right) rect.right = rcClient.right; dwStyle |= WS_BORDER|WS_CHILD|WS_VISIBLE|ES_AUTOHSCROLL;
CEdit *pEdit = new CInPlaceEdit(nItem, nCol, GetItemText( nItem, nCol ));
pEdit->Create( dwStyle, rect, this, IDC_IPEDIT );
return pEdit;
}
Step 4: Handle the scroll messages
The CInPlaceEdit class is designed to destroy the edit control and delete the object when it loses focus. Clicking on the scrollbars of the ListView control does not take away the focus from the edit control. We therefore add handlers for the scrollbar messages which force focus away from the edit control by setting the focus to the list view control itself. void CMyListCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if( GetFocus() != this ) SetFocus();
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}void CMyListCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
if( GetFocus() != this ) SetFocus();
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}
Step 5: Handle EndLabelEdit
Like the built in edit control for the first column, our edit control also sends the LVN_ENDLABELEDIT notification when the edit is completed. If this notification message isn’t already being handled, add a handler so that any changes made with the edit control can be accepted. void CMyListCtrl::OnEndLabelEdit(NMHDR* pNMHDR, LRESULT* pResult)
{
LV_DISPINFO *plvDispInfo = (LV_DISPINFO *)pNMHDR;
LV_ITEM *plvItem = &plvDispInfo->item; if (plvItem->pszText != NULL)
{
SetItemText(plvItem->iItem, plvItem->iSubItem, plvItem->pszText);
}
*pResult = FALSE;
}