VS2010/MFC 获取ListControl鼠标点击位置

C++/MFC 专栏收录该内容
220 篇文章 1 订阅

1、引言

       HitTest是命中测试的意思。在使用MFC编程的时候,在列表视图中通常会涉及到需要获取鼠标当前位置所对应的元素。这种通过光标位置来获得相应元素项的操作我们称之为命中测试。

2、获取光标位置

网上有人这样处理:

   DWORDdwPos = ::GetMessagePos();                                 //获得包含坐标信息的DWORD类型

 CPointpt(LOWORD(dwPos), HIWORD(dwPos));               //将坐标值转换为CPoint类型

    ScreenToClient(&pt);                                                                //将屏幕坐标转换为窗口客户区坐标

考虑到兼容性、可移植性等不建议这样处理,原因如下:

GetMessagePos

外文名
GetMessagePos                                                                    
函数原型
     DWORD GetMessagePos(VOID)
返回值
返回值给出光标位置的X,y坐标
速    查
Windows NT:3.1及以上版本
函数功能:该函数返回表示屏幕坐标下光标位置的长整数值。此位置表示当上一消息由GetMessage取得时鼠标占用的点。
参数:无。
返回值:返回值给出光标位置的X,y坐标。X坐标在低位整数,y坐标在高位整数。
备注:如前所述,X坐标在返回值的低位整数,y坐标在高位整数(都表示有符号值,因为在多显示器的系统里可取得负值)。如果返回值赋给了一个 变量,可用MAKEPOINT宏从返回值取得POINT结构。也可用GET_X_LPARAM或GET_Y_LPARAM宏来抽取X,y坐标,取得的坐标为屏幕坐标,并不是客户区坐标。
要得到光标的当前位置而不是上一个消息发生时的位置,调用函数GetCursorPos。
要点:不要用LOWORD或HIWORD宏来抽取鼠标位置的x,y坐标,因为在多显示器的系统里将返回不正确的结果。多显示器的系统里可取得负的x, y坐标,但LOWORD和HIWORD将坐标当作无符号量。
Windows CE下,对那些使用记录笔而不是鼠标的设备,光标位置是指当上一信息由GetMessage取得时,记录笔在触屏上的位置。
速查:Windows NT:3.1及以上版本;Windows:95及以上版本;Windows CE:1.0及以上版本;头文件:winuser.h;输入库:user32.lib。

正确处理方式如下:

CPoint  point;  
GetCursorPos(&point); 

3、在ListControl中获取当前选中项

资源视图-->选中ListControl控件-->属性中点击闪电符号-->添加NM_CLICK(即鼠标通知消息),在响应函数OnNMClick****(NMHDR *pNMHDR, LRESULT *pResult)中添加如下代码:

//获取当前光标位置

CPoint  point;  
GetCursorPos(&point);

 //将屏幕坐标转到客户区坐标
m_list.ScreenToClient(&point);  (注意:CListControl m_list)

或者

ScreenToClient(this,&point);也可以实现屏幕坐标转客户区坐标

参考:

ScreenToClient

顾名思义:ScreenToClient也就是Screen(屏幕坐标) 到 Client(客户区坐标)的转换。也就是说这个函数可以把你在屏幕上鼠标的位置转换为你打开的程序的客户区的坐标(位置)。

函数功能:该函数把 屏幕上指定点的屏幕 坐标转换成用户坐标。
函数原型:BOOL ScreenToClient(HWND hWnd, LPPOINT lpPoint);
BOOL ScreenToClient(
HWND hWnd ,// handle to window
LPPOINT lpPoint// screen coordinates
);

hWnd

指向窗口的句柄,此窗口的用户空间将被用来转换。

lpPoint

指向POINT结构指针,该结构含有要转换的屏幕坐标。

返回值

如果函数调用成功,返回值为非零值,否则为零。


LVHITTESTINFO

typedef struct _LVHITTESTINFO {
  POINT pt;    //输入
  UINT  flags; //输出
  int   iItem;//输出
  int   iSubItem;//输出
  int   iGroup;//输出
} LVHITTESTINFO, *LPLVHITTESTINFO;

上面这个结构体给定pt值后,在应用命中测试(hittest)之后,其他三个参数就可以获取到数据。

LVHITTESTINFO info;  
info.pt = point;  
int Itsub = m_list.SubItemHitTest(&info);  
int row = info.iItem;//行号从0开始
int col = info.iSubItem;//列号从0开始
UINT UtEST = info.flags;//一般点击在可编辑的列上返回#define LVHT_ONITEMLABEL        0x00000004,点击到控件上的其他地方返回#define LVHT_NOWHERE            0x00000001

参考:C:\Program Files\Microsoft SDKs\Windows\v7.0A\Include\CommCtrl.h
#define LVHT_NOWHERE            0x00000001
#define LVHT_ONITEMICON         0x00000002
#define LVHT_ONITEMLABEL        0x00000004
#define LVHT_ONITEMSTATEICON    0x00000008
#define LVHT_ONITEM             (LVHT_ONITEMICON | LVHT_ONITEMLABEL | LVHT_ONITEMSTATEICON)

#define LVHT_ABOVE              0x00000008
#define LVHT_BELOW              0x00000010
#define LVHT_TORIGHT            0x00000020
#define LVHT_TOLEFT             0x00000040


#define LVHT_EX_GROUP_HEADER       0x10000000
#define LVHT_EX_GROUP_FOOTER       0x20000000
#define LVHT_EX_GROUP_COLLAPSE     0x40000000
#define LVHT_EX_GROUP_BACKGROUND   0x80000000
#define LVHT_EX_GROUP_STATEICON    0x01000000
#define LVHT_EX_GROUP_SUBSETLINK   0x02000000
#define LVHT_EX_GROUP              (LVHT_EX_GROUP_BACKGROUND | LVHT_EX_GROUP_COLLAPSE | LVHT_EX_GROUP_FOOTER | LVHT_EX_GROUP_HEADER | LVHT_EX_GROUP_STATEICON | LVHT_EX_GROUP_SUBSETLINK)
#define LVHT_EX_ONCONTENTS         0x04000000 // On item AND not on the background
#define LVHT_EX_FOOTER             0x08000000


参考:https://msdn.microsoft.com/zh-cn/vstudio/bb774754关于该结构体的定义



其他相关:CListControl类中有下面三个函数

    // Determines the visual feature of a subitem control under
    // the specified point.
    int SubItemHitTest(_In_ LPLVHITTESTINFO pInfo);


    // Determines the visual feature of the control under
    // the specified point.
    int HitTest(_In_ LVHITTESTINFO* pHitTestInfo) const;
    int HitTest(_In_ CPoint pt, _In_opt_ UINT* pFlags = NULL) const;


注意体会区别,使用HitTest无法获取iSubItem的值,只能获得iItem的值,使用SubItemHitTest就可以获得iItem和iSubItem的值。



总结:一般常用的如下

void C*****Dlg::OnNMClick***(NMHDR *pNMHDR, LRESULT *pResult)
{
    LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
    // TODO: 在此添加控件通知处理程序代码
    CPoint  point;  
    GetCursorPos(&point);
    //将屏幕坐标转到客户区坐标
    m_list.ScreenToClient(&point);  (Glg.h文件中定义    CListCtrl m_list;)

    LVHITTESTINFO info;  
    info.pt = point;  
    int Itsub = m_list.SubItemHitTest(&info); 
    int row = info.iItem;//行号从0开始
    int col = info.iSubItem;//列号从0开始

}

MSDN给出的例子如下:

void CListCtrlDlg::OnDblClk(NMHDR* pNMHDR, LRESULT* pResult)
{
	UNREFERENCED_PARAMETER(pResult);

	LPNMITEMACTIVATE pia = (LPNMITEMACTIVATE)pNMHDR;
	LVHITTESTINFO lvhti;

	// Clear the subitem text the user clicked on.
	lvhti.pt = pia->ptAction;
	m_myListCtrl.SubItemHitTest(&lvhti);

	if (lvhti.flags & LVHT_ONITEMLABEL)
	{
		m_myListCtrl.SetItemText(lvhti.iItem, lvhti.iSubItem, L"要输入的内容");
	

详细代码见:




  • 1
    点赞
  • 0
    评论
  • 6
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值