欢迎光临
我们一直在努力

VBA获取树视图节点矩形Rect

本期细讲一个树视图控件的消息,叫做TVM_GETITEMRECT,用来获取树视图节点的矩形信息。这个节点矩形的用途非常大,像是绘制圆角矩形边框、填充背景等,都要用到它。

一、如何在VBA中使用TVM_GETITEMRECT消息?

微软官方文档只给了C语言的参考代码,可我们是VBA环境,要想使用就得进行代码转换。你可别小瞧了这个代码转换,在网上可是几乎搜不到类似的VBA案例。这意味着,自学者要使用TVM_GETITEMRECT消息实现一些功能,就要进行大量的研究和试错,先不说时间长短,哪怕真研究出了能用的代码了也很少会发到网上分享给大家的……

这个问题的难点是处理TVM_GETITEMRECT消息的lParam参数,用户需要将节点句柄先赋值给RECT结构的第一个成员Left上,然后才能调用SendMessage返回有效的矩形信息。其中,节点句柄在64位环境下类型为LongPtr,RECT结构成员Left的类型为Long,这个类型不匹配的问题就是关键点

这个问题的解决需要涉及内存知识。在64位下,句柄的类型为8字节的LongPtr;在32位下,句柄的类型为4字节的Long。这个时候直接将8字节的LongPtr赋值给4字节的Long是完全行不通的。但是你可以把LongPtr的低4位和高4位拆解开赋值,比如分别赋值给RECT结构的前两个成员:Left和Top,Left存低4位,Top存高4位。这样发送消息时系统将Left和Top共8字节的内存值解释为64位句柄,于是就可以正常的返回矩形信息了。这样是不是很巧妙啊?

以下是正确的使用方法,适配64/32位系统:

#If VBA7 And Win64 Then
Private Function TreeviewGetNodeRect(ByVal TreeView As LongPtr, ByVal Node As LongPtr) As RECT
#Else
Private Function TreeviewGetNodeRect(ByVal TreeView As Long, ByVal Node As Long) As RECT
#End If
Dim Ret As RECT
RtlMoveMemory Ret.Left, ByVal VarPtr(Node), 4
RtlMoveMemory Ret.Top, ByVal (VarPtr(Node) + 4), 4 '64位必须。32位下可注释掉,也可以不用。复制给Ret.Top的值会被TVM_GETITEMRECT消息返回值填充。
SendMessageA TreeView, TVM_GETITEMRECT, Nuptr, ByVal Ret
TreeviewGetNodeRect = Ret
End Function

二、最直观的应用案例

以下案例使用TVM_GETITEMRECT消息配合自定义绘制,实现树视图节点的圆角矩形背景填充。

使用自定义绘制的树视图到底有多强

三、最有意思的AI回答环节哈哈

最有意思的是,你无论去问哪个国产AI,它给出的回答莫过于以下几种,都是错误回答。提示词如下,请尽情尝试:

“如何在VBA中使用TVM_GETITEMRECT消息?在VBA中使用CreateWindowEx函数创建了一个窗口类为WC_TREEVIEW的树视图控件Treeview,里面有一些节点,我现在需要获取选中项的节点矩形,通过MsgBox的方式输出。但不清楚TVM_GETITEMRECT的使用方法,无法正确为RECT结构进行句柄赋值。请给出一个完整的实现过程,包含API函数、常量、结构和消息等代码。”

1. 激进型回答

这种丝毫不考虑类型匹配问题直接采用RECT.Left = Node语句,把节点句柄赋值给Left成员,属于是有思路无脑冲型

2. 保守型回答

先使用CLng将节点句柄转换为Long类型,再采用RECT.Left = Node语句将节点句柄赋值给Left成员,属于是有点实力但不多

3. 创新型回答

修改RECT结构的第一个成员类型:在64位系统下,Left成员类型为LongPtr;在32位系统下,Left成员类型为Long。这种方法咋一看是没什么问题,但在64位时RECT结构的消息返回值顺序会被打乱,提取不到正确的成员值,属于痛点针对型

来看看你的AI属于哪种吧!

四、相关文章

https://mp.weixin.qq.com/s/axq9ONXoNCP_TWiufvS30Q

赞(0)
未经允许不得转载:171主机测评 » VBA获取树视图节点矩形Rect
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址