yhxhappy 发表于 2017-12-16 17:07:22

[已解决] 如何获取ListView中鼠标点中单元格的内容

本帖最后由 yhxhappy 于 2017-12-17 12:06 编辑

我想复制 ListView 中 鼠标所点中行单元格 数据,所以就做了一个右键菜单,鼠标在ListView中点击右键时弹出菜单复制内容。

现在的问题是:如果ListView中一旦有水平滚动条,并且拖动后,获取的行列数据就不准了。
以下是演示的代码,初始状态是可以获取的,一旦向右滚动获取的内容就不准。

自己研究解决了,增加滚动条的补偿,_GUIScrollBars_GetScrollInfoPos 获取滚动条的位置,见第51,54行代码
实际还是有些误差,大概5个像素左右,当点击两列之间时会发现。但对我影响不大就不研究了。
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#Include <GuiScrollBars.au3>


Opt("MouseCoordMode", 0)                ;设置用于鼠标函数的 coords 坐标参照 = 激活窗口的相对坐标

$GUI = GUICreate("listview 列表视图", 300, 250)
$listview = GUICtrlCreateListView("列 1|列 2 |列 3 |列 4 |列 5 |列 6 |列 7", 10, 10, 280, 150)
GUICtrlCreateListViewItem("项目 1|子项 12|子项 13|项目 14|子项 15|子项 16|子项 17", $listview)
GUICtrlCreateListViewItem("项目 2|子项 22|子项 23|项目 24|子项 25|子项 26|子项 27", $listview)
GUICtrlCreateListViewItem("项目 3|子项 32|子项 33|项目 34|子项 35|子项 36|子项 37", $listview)

$ColumnNum = _GUICtrlListView_GetColumnCount($listview)                ;取得列数
Global $xyArray[$ColumnNum]
For $i = 0 To $ColumnNum-1
   $ItemXY = _GUICtrlListView_GetSubItemRect($listview, 0, $i)
   $xyArray[$i] = $ItemXY
Next

;===右键 系统菜单窗口=======================================================================
$OptionsDummy = GUICtrlCreateDummy()                                                                ;创建一个虚拟控件,让菜单依托于控件, 这个控制必须创建于主窗口,否则不能触发事件
$ContextMenu = GUICtrlCreateContextMenu($OptionsDummy)                                ;创造菜单
$CopyMenu = GUICtrlCreateMenuItem("复制单元格内容", $ContextMenu)        ;"复制单元格内容"
;==========================================================================================

Global $ClickLVRowIndex        ;LV选中的行序号
Global $ClickLVRowIndex ;LV鼠标所在的列序号

GUISetState()

While 1
   Switch GUIGetMsg()
   Case $GUI_EVENT_CLOSE
          Exit
   Case $GUI_EVENT_SECONDARYUP
          $Pos = GUIGetCursorInfo($GUI)                                                                        ;取得鼠标当前停留控件的信息
          If @error Or Not IsArray($Pos) Then ContinueLoop
          If $Pos <> $listview Then ContinueLoop                                                ;鼠标没有点在LV内,则返回
          If Not StringInStr(ControlGetFocus($GUI), "SysListView") Then ContinueLoop                ;如果当前激活的控件不是LV,则返回

          $ClickLVRowIndex = _GUICtrlListView_GetHotItem($listview)                ;取得选中项的行序号
          If $ClickLVRowIndex < 0 Then ContinueLoop                                                ;没有项目被选中,则返回

          $GPos = WinGetPos($GUI)                                                                                ;取得窗口的坐标
          If @error Or Not IsArray($GPos) Then ContinueLoop

          $MPos = MouseGetPos()                                                                                        ;取得鼠标相对于窗口的坐标
          If @error Then ContinueLoop

          $ScrollBarsPOS = _GUIScrollBars_GetScrollInfoPos(GUICtrlGetHandle($listview), $SB_HORZ)                ;LV控件水平滚动条位置

          For $i = UBound($xyArray)-1 To 0 Step -1                                                ;当前鼠标X坐标 在 列坐标数组内 从大到小对比
               If $MPos+$GPos+$ScrollBarsPOS-10 > $xyArray[$i]+$GPos Then                        ;10是LV的X坐标,如果X坐标大于某列的X坐标,且小于下一列的X坐标,则说明鼠标点击了该列
                        $ClickLVColumnIndex = $i
                        ExitLoop
               EndIf
          Next

          DllCall("user32.dll", "int", "TrackPopupMenuEx", "hwnd", GUICtrlGetHandle($ContextMenu), "int", 0, "int", $GPos+$MPos, "int", $GPos+$MPos, "hwnd", $GUI, "ptr", 0)        ; 显示指定坐标(x,y), 属于一个指定 GUI 窗口(hWnd)的弹出菜单(hMenu).
   Case $CopyMenu
          $String = _GUICtrlListView_GetItemText($listview, $ClickLVRowIndex, $ClickLVColumnIndex)
          MsgBox(0, "鼠标点中的单元格内容", $String)
   EndSwitch
WEnd

Alam 发表于 2017-12-16 21:24:14

搜索一下 ListView 就地编辑的源码例子吧.

Alam 发表于 2017-12-16 21:24:20

搜索一下 ListView 就地编辑的源码例子吧.

yhxhappy 发表于 2017-12-17 10:13:33

回复 3# Alam


    我搜索了关于 ListView 原地编辑的帖子。我自己以前也发过同功能的源码。
都是ListView刚好够显示,没有涉及到横向滚动条的。
页: [1]
查看完整版本: [已解决] 如何获取ListView中鼠标点中单元格的内容