Click to See Complete Forum and Search --> : ListView's ContextMenu


April 6th, 1999, 07:16 AM
Hi,

I use VC5.0 on NT4.

I need to know how to detect when a user has right-clicked on an item in a listview, and not just anywhere in the client area. I only want to display the
context menu when there has been right clicked on an item in the view.
I think I'll have to handle the OnRButtonClick message, but do not know what
to do then.

Any help you can give me will be much appreciated.

Thanks in advance.

Dave Lorde
April 6th, 1999, 09:41 AM
If you handle the NM_CLICK notification, you will receive an NMLISTVIEW structure as the lParam argument. This has all the information you need:

typedef struct tagNMLISTVIEW
{
NMHDR hdr;
int iItem;
int iSubItem;
UINT uNewState;
UINT uOldState;
UINT uChanged;
POINT ptAction;
LPARAM lParam;
} NMLISTVIEW, FAR *LPNMLISTVIEW;

Have a look at "List View Control Notification Messages" in the online docs.

Also check out the List Control area on this site, there are probably suitable examples there.

Dave

sajal s
February 28th, 2001, 11:24 AM
1. Map CListView's OnContextMenu
2. Get the Window Rect of List Control,
3. Compare it with mouse coordinates to determine whether it is over list control
4. if not , return, else continue with right click popup menu

BobClarke
February 28th, 2001, 11:35 AM
Here's some sample code for a right-click handler that does what you want.
If the user right-clicks over a list control item or subitem, the context menu shows "Add," "Edit" and "Delete." If the user right-clicks off of any row (i.e., on a row of white space), then the context menu contains just "Add."

Ignore the SetCurrentAdvisor() call, it has nothing to do with your problem.
 

void CAdvisorsPage::OnRclickListReps(NMHDR* pNMHDR, LRESULT* pResult)
{
SetCurrentAdvisor();

NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
CPoint pt(pNMListView->ptAction);
CMenu menu;
menu.LoadMenu(IDM_LISTCTRL); // our context menu
CMenu* pContextMenu = menu.GetSubMenu(0);

// Only the Fee Schedules page uses Clone
menu.RemoveMenu(ID_LISTCTRL_CLONE, MF_BYCOMMAND);

// Make sure something is there before we show the menu.
// If nothing is there, shorten the menu to just "Add..."
int nCol = 0;
CHeaderCtrl* pHdr = m_listctrlReps.GetHeaderCtrl();
ASSERT(pHdr);
int nIndex = m_StdRt.HitTestEx( pt,&nCol, m_listctrlReps, pHdr->GetItemCount());
if(m_CurrentAdvisor.m_FirmID < 0 || nIndex == -1)
{
menu.RemoveMenu(ID_LISTCTRL_EDIT, MF_BYCOMMAND); // remove "Edit..."
menu.RemoveMenu(ID_LISTCTRL_DELETE, MF_BYCOMMAND); // remove "Delete..."
}

POINT p;
p.x = pt.x;
p.y = pt.y;
::ClientToScreen(pNMHDR->hwndFrom, &p);
int nID = pContextMenu->TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RETURNCMD,
p.x, p.y, this);

// if() used instead of case to avoid overhead of instantiating
// possibly unused resources outside the switch statement
if(nID == ID_LISTCTRL_ADD)
AdvisorInsert();
else if(nID == ID_LISTCTRL_EDIT)
AdvisorEdit();
else if(nID == ID_LISTCTRL_DELETE)
AdvisorDelete();

// The menu is a temporary MFC object, no need to delete it.

*pResult = 0;
}

///////////////////////////////////////
// HitTestEx() code:
 
/*
Name: HitTestEx()
Description: Determines row and column of a mouse click in the list control
*/

int CStdRoutines::HitTestEx( CPoint point, int *nCol, CListCtrl& list, int nColumnCount)
{
int colnum = 0;
int row = list.HitTest( point, NULL );

if( nCol ) *nCol = 0;

// Make sure that the ListView is in LVS_REPORT mode
if( (GetWindowLong(list.m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
return row;

// Get the top and bottom row visible
row = list.GetTopIndex();
int bottom = row + list.GetCountPerPage();

if( bottom > list.GetItemCount() )
bottom = list.GetItemCount();

// Loop through the visible rows
for( ;row <= bottom;row++)
{
// Get bounding rect of item and check whether point falls in it.
CRect rect;
list.GetItemRect( row, &rect, LVIR_BOUNDS );
if( rect.PtInRect(point) )
{
// Now find the column
for( colnum = 0; colnum < nColumnCount; colnum++ )
{
int colwidth = list.GetColumnWidth(colnum);
if( point.x >= rect.left && point.x <= (rect.left + colwidth ) )
{
if( nCol ) *nCol = colnum;
return row;
}
rect.left += colwidth;
}
}
}
return -1;
}

///////////////////////////////////////
 
// The resource info for the context menu:
IDM_LISTCTRL MENU DISCARDABLE
BEGIN
POPUP ""
BEGIN
MENUITEM "&Add...", ID_LISTCTRL_ADD
MENUITEM "&Edit...", ID_LISTCTRL_EDIT
MENUITEM "&Delete...", ID_LISTCTRL_DELETE
MENUITEM "&Clone...", ID_LISTCTRL_CLONE
END
END