[ATL/WTL]_[初级]_[如何获取ListView点击的单元格区域]

news2024/11/9 1:40:01

场景

  1. 在做Win32/WTL开发时,CListViewCtrl控件是常用的表格控件。有时候自绘listview时,需要在单元格上绘制小图标,并且小图标能响应鼠标点击的操作。 那么如何实现判断是否点击了小图标呢?

说明

  1. 要响应点击单元格上的小图标,那么需要判断点击的坐标POINT是否在小图标的区域CRect里。 坐标很容易得到,点击消息都会带坐标值。 小图标区域需要获取单元格所在区域,之后在通过相对位置获取小图标的区域。也就是只要获取点击的单元格区域就可以获取小图标区域。所以下边来看看如何获取点击的单元格所在区域。

  2. listview要响应点击操作,可以使用传统的WM_LBUTTONUP消息,也可以使用NM_CLICK通知。

  3. 如果是响应WM_LBUTTONUP消息,可以使用CListViewCtrl.SubItemHitTest()方法,它通过鼠标点击坐标来计算所在的行和列数值nIteminfo.iSubItem[3]

    LVHITTESTINFO info = {0};
    info.pt = lpnmlv->ptAction;
    auto nItem = listview_.SubItemHitTest(&info);
    
  4. 如果是响应NM_CLICK通知,它的lParam就可以强制转换为LPNMITEMACTIVATE指针类型[2]。这个类型里可以使用它的成员iItem行,iSubItem列和ptAction点击坐标。 通过行和列值可以通过listview方法GetSubItemRect获取所在单元格的区域[1]。 注意:这个方法只能获取第一列以上的区域,传递第0列获取的是整行的区域,所以要获取第0列的区域,还需要使用方法GetColumnWidth(0)来进行换算。

listview_.GetSubItemRect(p->iItem,p->iSubItem,LVIR_BOUNDS,&rect); // 第1列以上
if(!p->iSubItem){
	// 第0列计算
	auto width = listview_.GetColumnWidth(0);
	rect.right = rect.left+width; 
}

例子

View.h

// View.h : interface of the CView class
//
/

#pragma once

#include <utility>
#include <string>


enum
{
	kMyStaticId = WM_USER+1,
	kMyListViewId,
	kMyCheckListViewId,
	kMySortListViewId,
	kMyButtonId
};

class CView : public CWindowImpl<CView>
{
public:
	DECLARE_WND_CLASS(NULL)

	BOOL PreTranslateMessage(MSG* pMsg);

	BEGIN_MSG_MAP_EX(CView)
		MSG_WM_CREATE(OnCreate)
		MESSAGE_HANDLER(WM_PAINT, OnPaint)
		NOTIFY_HANDLER(kMyListViewId,NM_CLICK,OnNMClickListResult)
		NOTIFY_HANDLER(kMyListViewId,LVN_HOTTRACK,OnListItemHotTrack)
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()

// Handler prototypes (uncomment arguments if needed):
//	LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
//	LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
//	LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
	int OnCreate(LPCREATESTRUCT lpCreateStruct);
	LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
	void UpdateLayout();
	LRESULT OnNMClickListResult(int idCtrl,LPNMHDR pnmh,BOOL &bHandled);
	void AddMockData(CListViewCtrl& listview);
	void OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl);
	LRESULT OnListItemHotTrack(int idCtrl,LPNMHDR pnmh,BOOL &bHandled);

private:
	std::wstring GetControlText(HWND hwnd,wchar_t* buf = NULL);

	CListViewCtrl listview_;

	CFont font_normal_;
	CFont font_bold_;

	CBrushHandle brush_white_;
	CBrushHandle brush_hollow_;
	CBrush brush_red_;
	CToolTipCtrl tooltip_;
	TCHAR strToolTipText_[MAX_PATH];

public:
};

View.cpp

// View.cpp : implementation of the CView class
//
/

#include "stdafx.h"
#include "resource.h"
#include <utility>
#include <sstream>
#include <assert.h>

#include "View.h"
#include <CommCtrl.h>
#include <string>
#include <regex>

using namespace std;

BOOL CView::PreTranslateMessage(MSG* pMsg)
{
	return FALSE;
}

LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
	CPaintDC dc(m_hWnd);
	CMemoryDC mdc(dc,dc.m_ps.rcPaint);

	CRect rect_client;
	GetClientRect(&rect_client);
	mdc.FillSolidRect(rect_client,RGB(255,255,255));
	//TODO: Add your drawing code here

	return 0;
}

static HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{
	LOGFONT lf; 
	memset(&lf, 0, sizeof(LOGFONT)); // zero out structure 
	lf.lfHeight = pixel; // request a 8-pixel-height font
	if(bold)
	{
		lf.lfWeight = FW_BOLD;  
	}
	lstrcpy(lf.lfFaceName, font_name); // request a face name "Arial"
	
	HFONT font = ::CreateFontIndirect(&lf);
	return font;
}


std::wstring CView::GetControlText(HWND hwnd,wchar_t* buf)
{
	auto length = ::GetWindowTextLength(hwnd);
	bool bufNull = false;
	if(!buf){
		buf = new wchar_t[length+1]();
		bufNull = true;
	}
	
	::GetWindowText(hwnd,buf,length+1);
	std::wstring str(buf);

	if(bufNull)
		delete []buf;

	return str;
}

static std::wstring GetProductBinDir()
{
	static wchar_t szbuf[MAX_PATH];  
	GetModuleFileName(NULL,szbuf,MAX_PATH);  
    PathRemoveFileSpec(szbuf);
	int length = lstrlen(szbuf);
	szbuf[length] = L'\\';
	szbuf[length+1] = 0;
	return std::wstring(szbuf);
}

LRESULT CView::OnNMClickListResult(int idCtrl,LPNMHDR pnmh,BOOL &bHandled)
{
	auto p = (LPNMITEMACTIVATE) pnmh;
	int row = p->iItem;
	if(row == -1)
		return 0;
	
	CRect rect;
	// The one-based index of the subitem.
	// LVM_GETSUBITEMRECT message (Commctrl.h) - Win32 apps | Microsoft Learn https://learn.microsoft.com/en-us/windows/win32/controls/lvm-getsubitemrect
	listview_.GetSubItemRect(p->iItem,p->iSubItem,LVIR_BOUNDS,&rect);
	if(!p->iSubItem){
		auto width = listview_.GetColumnWidth(0);
		rect.right = rect.left+width;
	}

	auto header = listview_.GetHeader();
	int nColumnCount = header.GetItemCount();
	wstringstream wss;
	static wchar_t buf[MAX_PATH];
	memset(buf,0,sizeof(buf));
	listview_.GetItemText(row,p->iSubItem,buf,MAX_PATH);
	
	wss << buf << L": Rect:[" << 
		rect.left << L"," << 
		rect.top << L"," <<
		rect.Width() << L"," <<
		rect.Height() << L"] Position:[" << 
		p->ptAction.x << L"," << p->ptAction.y << L"]";
	wstring result = wss.str();

	MessageBox(result.c_str());
	return 0;
}

void CView::AddMockData(CListViewCtrl& listview)
{
	listview.InsertColumn(0,L"No.",LVCFMT_LEFT,40);
	listview.InsertColumn(1,L"Name",LVCFMT_LEFT,200);
	listview.InsertColumn(2,L"Website",LVCFMT_LEFT,200);
	listview.InsertColumn(3,L"Level",LVCFMT_LEFT,200);

	wchar_t buf[MAX_PATH] = {0};
	LVCOLUMN co;
	memset(&co,0,sizeof(co));
	co.mask = LVCF_TEXT;
	co.pszText = buf;
	co.cchTextMax = MAX_PATH;
	listview.GetColumn(1,&co);
	std::wstring c0Text(buf);

	listview.GetColumn(2,&co);
	std::wstring c1Text(buf);
	
	listview.GetColumn(3,&co);
	std::wstring c2Text(buf);

	for(int i = 0; i<10;++i){
		
		wsprintf(buf,L"%d",i+1);
		listview.AddItem(i,0,buf);

		wsprintf(buf,(c0Text+L"-%d").c_str(),i);
		listview.AddItem(i,1,buf);

		wsprintf(buf,(c1Text+L"-%d").c_str(),i);
		listview.AddItem(i,2,buf);

		wsprintf(buf,(c2Text+L"-%d").c_str(),i);
		listview.AddItem(i,3,buf);
	}
}

LRESULT CView::OnListItemHotTrack(int idCtrl,LPNMHDR pnmh,BOOL &bHandled)
{
	bHandled = TRUE;
	LPNMLISTVIEW lpnmlv = (LPNMLISTVIEW) pnmh;
	
	// 获取坐标所在的Item(行)和SubItem(列).
	LVHITTESTINFO info = {0};
	info.pt = lpnmlv->ptAction;
	auto nItem = listview_.SubItemHitTest(&info);
	if(nItem == -1)
		return 0;

	static int kShowTooltipColumn = 2;
	static wchar_t buf[MAX_PATH] = {0};
	if(info.iSubItem == kShowTooltipColumn){
		listview_.GetItemText(nItem,info.iSubItem,buf,MAX_PATH);
		tooltip_.UpdateTipText(buf,listview_);

		if(!listview_.GetToolTips()) 
			listview_.SetToolTips(tooltip_);
	}else{
		if(listview_.GetToolTips())
			listview_.SetToolTips(NULL);
	}

	return 0;
}

int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	font_normal_ = ::GetFont(16,false,L"Arial");
	font_bold_ = ::GetFont(16,true,L"Arial");

	// 1.创建CListViewCtrl
	listview_.Create(m_hWnd,0,NULL,WS_CHILD | WS_TABSTOP |WS_VISIBLE
		|LVS_ALIGNLEFT|LVS_REPORT|LVS_SHOWSELALWAYS|WS_BORDER,0,kMyListViewId);
	// 2.如果需要监听在listview鼠标移动消息,创建时传入LVS_EX_TRACKSELECT扩展样式。
	listview_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_DOUBLEBUFFER|LVS_EX_TRACKSELECT);
	listview_.SetFont(font_normal_);
	auto header = listview_.GetHeader();
	header.SetFont(font_bold_);
	listview_.SetBkColor(RGB(255,255,255));
	AddMockData(listview_);

	tooltip_.Create(listview_,NULL,NULL,TTS_NOPREFIX);
	tooltip_.AddTool(listview_,L"");
	listview_.SetToolTips(tooltip_);
	listview_.SetHoverTime(10);

	brush_hollow_ = AtlGetStockBrush(HOLLOW_BRUSH);
	brush_white_ = AtlGetStockBrush(WHITE_BRUSH);
	brush_red_.CreateSolidBrush(RGB(255,0,0));
	UpdateLayout();

	return 0;
}

void CView::OnCommandIDHandlerEX(UINT uNotifyCode, int nID, CWindow wndCtl)
{
		
}

void CView::UpdateLayout()
{
	CRect rect;
	GetClientRect(&rect);

	CClientDC dc(m_hWnd);
	dc.SelectFont(font_normal_);

	CSize size_control(700,300);
	CRect rect_control = CRect(CPoint(20,20),size_control);
	listview_.MoveWindow(rect_control);

}

项目资源

https://download.csdn.net/download/infoworld/87881180

图示

在这里插入图片描述

参考

  1. LVM_GETSUBITEMRECT message (Commctrl.h)

  2. NM_CLICK (list view) notification code (Commctrl.h)

  3. LVM_SUBITEMHITTEST message (Commctrl.h)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/624230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB笔记

mongoDB基础知识 MongoDB的三个核心特性&#xff1a;灵活设计&#xff08;No Schema&#xff09;、高可用和分布式&#xff08;可平行扩展&#xff09;&#xff0c;另外MongoDB自带数据压缩功能&#xff0c;使得同样的数据存储所需的资源更少。 No Schema&#xff08;BJSON&a…

NeRF-Diffusion系列文章阅读

文章目录 前置知识《Latent-NeRF for Shape-Guided Generation of 3D Shapes and Textures》【CVPR23】《NeRDi: Single-View NeRF Synthesis with Language-Guided Diffusion as General Image Priors》【CVPR23】《SparseFusion: Distilling View-conditioned Diffusion for …

【系统找不到D盘指定驱动设备之解决方法】

文章目录 1.原因2.解决经过3.最终解决办法 1.原因 今天在搞课设&#xff0c;突然之间电脑一顿卡&#xff0c;然后整个电脑屏幕空白&#xff0c;D盘以及所有的安装软件都不见了。点击屏幕出现提示系统找不到指定驱动设备等等提示&#xff0c;查看此电脑发现D盘神奇的消失了。 …

Kafka面试题01

1、kafka有哪些特点 高吞吐&#xff0c;低延迟 可以热扩展 并发度高 具有容错性&#xff08;即使挂的只剩下一台也可以正常工作&#xff09; 可靠性高2、请简述你在那些场景下会选择kafka&#xff1f;kafka的应用 日志收集&#xff1a; 一个公司可以用kafka收集各种服务的log…

B站、抖音上那些4K、60帧视频是如何修复的?

如何把一个不清晰的视频变成高清的视频&#xff1f;今天就来教大家视频画质修复把720p的渣画质变成4K超清画质。 相信对于电影和后期爱好者来说&#xff0c;糊成马赛克的画质一定劝退了无数人&#xff0c;那不妨试试这个 牛学长视频修复工具 牛学长视频修复工具通过高级的AI…

Java网络开发(Tomcat)—— 登陆 和 注册功能 的实现 从html 到 jsp 迭代升级 session保存登陆信息

目录 引出登陆功能---从html到jsp1.登陆--用post请求2.用html文件的form表单登陆&#xff08;1&#xff09;index.html页面&#xff08;2&#xff09;login.html登陆的页面&#xff08;3&#xff09;LoginServlet.java处理输入信息的代码&#xff08;4&#xff09;登陆成功&…

ChatGPT提示大解析:如何有效定制Prompt并用插件管理

有时候&#xff0c;你可能在编程时遇到难题&#xff0c;需要解决方法。有时候&#xff0c;你在学习新的语言时&#xff0c;想要找到一位悉心的教师。又或者&#xff0c;你可能只是需要一些新的灵感&#xff0c;来润色你的文章。在所有这些情况下&#xff0c;ChatGPT都可以发挥巨…

轻量应用服务器哪款性价比高?

最近云服务器618活动正在火热进行中&#xff0c;选对时间入手自己心仪的云服务器其实可以为你省去一大笔费用&#xff0c;这里先开门见山将三家的云服务器活动粒度做个对比。 腾讯云 懂行的人一看这种配置性价比就会内心无比激动&#xff0c;按照平时的价格根本买不到这么实惠的…

JavaSE基础知识笔记

​1、基础语法 在一个Java源文件中可以声明多个class&#xff0c;但是最多只有一个类可以被声名为public&#xff0c;而且被声名为public的类的类名必须与源文件名相同。 计算机底层都以补码的方式来存储数据&#xff01;目的是为了简化计算机的结构设计&#xff0c;同时提升运…

如何在Moonbeam设置多重签名钱包,加固资产安全

Moonbeam Safe是以太坊上Safe&#xff08;先前名为Gnosis Safe&#xff09;的分叉。Safe于2018年正式推出&#xff0c;并发展成为了以太坊上知名的去中心化托管协议和集体资产管理平台。 Moonbeam Safe可用于创建多重签名Safe钱包&#xff0c;通过配置一个多签&#xff08;mul…

02.Web大前端时代之:HTML5+CSS3入门系列~H5结构元素

Web大前端时代之&#xff1a;HTML5CSS3入门系列&#xff1a;Web大前端时代之&#xff1a;HTML5CSS3入门系列 - 毒逆天 - 博客园 1.结构元素 可以理解为语义话标记&#xff0c;比如&#xff1a;以前这么写<div id"nav"></div> 现在偷懒写&#xff1a;&l…

JavaWeb笔记_SpringBoot原理

JavaWeb笔记_SpringBoot原理 配置优先级Bean管理获取BeanBean作用域第三方Bean SpringBoot原理自动配置原理ComponentScan组件扫描Import导入源码跟踪Conditional自定义starter创建aliyun-oss-spring-boot-starter模块创建aliyun-oss-spring-boot-autoconfigure 来源 配置优先级…

opencv、dlib、paddlehub人脸检测

opencv、dlib、paddlehub检测效果对比。dlib和paddlehub的效果相对好一点。 说明&#xff1a;本文只做人脸检测不识别&#xff0c;找识别的不用看本文。 ## 部署说明 # 1. 安装python或conda # 2. 安装依赖&#xff0c;pip install -r requirements.txt # 3. 192.168.1.41 修…

Docker 基本使用

安装 Linux安装 # 1、查看当前Linux系统版本 Linux系统版本需要>3.0 [rootzjrs_test2_152 ~]# uname -a Linux zjrs_test2_152 3.10.0-957.el7.x86_64 #1 SMP Thu Nov 8 23:39:32 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux [rootzjrs_test2_152 ~]# uname -r 3.10.0-957.el…

Baumer工业相机堡盟工业相机如何使用BGAPI SDK控制相机数据流的开启和关闭(C#)

Baumer工业相机堡盟工业相机如何使用BGAPI SDK控制相机数据流的开启和关闭&#xff08;C#&#xff09; Baumer工业相机Baumer工业相机BGAPI SDK的技术背景Baumer工业相机使用BGAPISDK控制相机数据流的方式1.引用合适的类文件2.使用BGAPISDK控制相机数据流的方式2.使用BGAPISDK控…

AOP--@DeclareParents--引入新功能

目录 引入 解析 示例 引入 Java不是动态语言&#xff1b;一旦类编译完成了&#xff0c;我们就很难再为该类添加新的功能了切面能够为现有的方法增加额外的功能&#xff0c;为什么不能为一个对象增加新的方法呢&#xff1f;实际上&#xff0c;利用被称为引入的AOP概念&#x…

从数据开始,构建值得信赖的生成式AI应用

生成式AI有望从根本上打开新世界机遇的大门&#xff1a;从能够个性化回复的对话式聊天机器人&#xff0c;到各种应用的代码&#xff0c;再到营销传播的定制化内容......生成式AI正在彻底改变企业的运作方式。越来越多的领先企业正在构建可信的生成式AI应用&#xff0c;让它们在…

信息共享、管理协作!工程劳务管理模板让企业内部更加通畅

随着建筑行业的快速发展&#xff0c;工程劳务管理变得越来越复杂&#xff0c;同时企业也需要更加高效地管理劳务人员的信息、工资、考勤等方面。因此&#xff0c;工程劳务管理系统应运而生&#xff0c;帮助企业解决这些问题。作为一款低代码开发平台&#xff0c;百数根据市面上…

面向 MSP 的IT管理

MSP&#xff08;管理服务提供商&#xff09;是通过建立自己的网络运作中心(NOC&#xff0c;Network Operating Center)来实施管理服务的。用户的网络通过WAN与MSP的NOC相连&#xff0c;并使用加密技术保证信息在网络上的传输安全。通过NOC&#xff0c;MSP可以实现远程的管理、实…

LVS负载均衡群集----DR部署

文章目录 一、数据包流向分析二、DR模式的特点三、LVS-DR中的ARP问题四、LVS单网段DR模式部署第一步配置负载调度器第二步设置两台节点服务器第三步设置DR 服务器第四步在本地查看调度服务器 一、数据包流向分析 &#xff08;1&#xff09;客户端发送请求到 Director Server&a…