【发布时间】:2017-01-03 00:14:05
【问题描述】:
我使用 WinApi 创建了一个树视图控件。我想捕捉鼠标点击复选框。通知消息 NM_CLICK 包含 NMHDR,其中没有关于被单击节点的信息。由于单击的节点可能与选定的节点不同,因此应该有一种方法可以找到已选中或未选中的节点,它可以是 HTREEITEM,或者在向树视图添加项目时插入了 lParam。我想实时捕获检查/取消检查。如何指定选中/取消选中哪个节点?任何帮助或链接表示赞赏。 阿布扎德先生
【问题讨论】:
我使用 WinApi 创建了一个树视图控件。我想捕捉鼠标点击复选框。通知消息 NM_CLICK 包含 NMHDR,其中没有关于被单击节点的信息。由于单击的节点可能与选定的节点不同,因此应该有一种方法可以找到已选中或未选中的节点,它可以是 HTREEITEM,或者在向树视图添加项目时插入了 lParam。我想实时捕获检查/取消检查。如何指定选中/取消选中哪个节点?任何帮助或链接表示赞赏。 阿布扎德先生
【问题讨论】:
我想实时捕捉检查/取消检查。我怎样才能 指定哪个节点被选中/取消选中?
对于此存在通知 TVN_ITEMCHANGING 和 TVN_ITEMCHANGED - 寻找 uStateNew 和 uStateOld 的成员 NMTVITEMCHANGE - 当树视图有复选框(TVS_CHECKBOXES 样式)时,它用作带有 2 个图像的状态图像列表- unchecked 和 checked。
所以state & TVIS_STATEIMAGEMASK 将在没有复选框时为0,INDEXTOSTATEIMAGEMASK(1) 为未选中,INDEXTOSTATEIMAGEMASK(2) 为选中。基于此信息,我们可以捕获鼠标单击复选框
通过使用TVN_ITEMCHANGING,您还可以在为此通知返回 TRUE 时阻止更改。如果您只需要通知 - 使用 TVN_ITEMCHANGED
case WM_NOTIFY:
{
union {
LPARAM lp;
NMTVITEMCHANGE *pnm;
NMHDR* phdr;
};
lp = lParam;
switch (phdr->code)
{
case TVN_ITEMCHANGING:
{
UINT CheckStateOld = pnm->uStateOld & TVIS_STATEIMAGEMASK;
UINT CheckStateNew = pnm->uStateNew & TVIS_STATEIMAGEMASK;
if (CheckStateNew != CheckStateOld)
{
PCSTR szstate = "??";
switch (CheckStateNew)
{
case INDEXTOSTATEIMAGEMASK(1):
szstate = "uncheck";
break;
case INDEXTOSTATEIMAGEMASK(2):
szstate = "check";
break;
}
DbgPrint("%p>%s\n", pnm->lParam, szstate);
}
}
return FALSE;
}
}
另请阅读How to Work With State Image Indexes
// Image 1 in the tree-view check box image list is the unchecked box. // Image 2 is the checked box. tvItem.state = INDEXTOSTATEIMAGEMASK((fCheck ? 2 : 1));
通知TVN_ITEMCHANGING 和TVN_ITEMCHANGED 从Windows Vista 开始可用。如果你也需要 XP 支持 - 在 xp 选项上使用 @IInspectable solution
【讨论】:
您可以发送TVM_HITTEST 消息(或使用TreeView_HitTest 宏)在给定客户端相对坐标的情况下查找树视图项。
要在生成NM_CLICK 消息时获取光标位置,请使用GetMessagePos API。
这允许您监视控件客户区域中的任何鼠标单击。如果您对标准树视图控件实现导致的状态更改感兴趣,则可以改为处理TVN_ITEMCHANGING 或TVN_ITEMCHANGED 通知。两者都提供NMTVITEMCHANGE 结构,其中hItem 标识正在更改的项目,lParam 携带特定于应用程序的数据。
【讨论】:
TVN_ITEMCHANGING 和 TVN_ITEMCHANGED 通知的信息已经在我用这个写了自己的答案 - 这在编辑历史记录中可见。这就是最小的不好:)