找回密码
 加入
搜索
查看: 10750|回复: 18

[AU3基础] 发现_GUICtrlListView_FindText搜索有个BUG,不支持中文完全匹配(已解决)

[复制链接]
发表于 2014-3-31 12:09:32 | 显示全部楼层 |阅读模式
本帖最后由 txm888 于 2014-4-1 07:28 编辑

近期问题多多,又发现_GUICtrlListView_FindText搜索中文有个严重问题,如果搜索关键字含中文,而控件里又没找到的话,是返回的0,而帮助文里说搜索不到返回-1
其次,搜索关键字若包含中文,搜索只能模糊匹配第一项,不能完全匹配,不管$fPartialOK = True是设置False还是True都不行,相反,搜索英文和数字是很好精确的,支持模糊和完全匹配
有没有哪位遇到这问题的啊?

_GUICtrlListView_FindText
--------------------------------------------------------------------------------
用指定文本搜索项目
#Include <GuiListView.au3>
_GUICtrlListView_FindText($hWnd, $sText[, $iStart = -1[, $fPartialOK = True[, $fWrapOK = True]]])
参数

$hWnd 控件句柄
$sText 匹配的文本
$iStart 开始搜索的基于 0 的项目索引 或设置为 -1, 从开始进行. 指定项目自身排除在外.
$fPartialOK 如果为真, 且项目文本已搜索文本开始,视为匹配
$fWrapOK 如果为真, 且未找到匹配项, 搜索将从第一项继续

返回值
成功: 基于 0 的项目索引失败: -1

备注
搜索大小写不敏感. 搜索仅对项目进行. 如果想搜索子项使用 _GUICtrlListView_FindInText.
#AutoIt3Wrapper_au3check_Parameters=-d -w 1 -w 2 -w 3 -w 4 -w 5 -w 6
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>

Opt('MustDeclareVars', 1)

$Debug_LV = False ; 检查传递给函数的类名, 设置为真并使用另一控件句柄观察其工作

_Main()

Func _Main()
    Global $iI, $hListView

    ; 创建界面
    GUICreate("ListView Find Text", 400, 300)
    $hListView = GUICtrlCreateListView("", 2, 2, 394, 268)
    GUISetState()

    ; 添加列
    _GUICtrlListView_AddColumn($hListView, "Items", 100)

    ; 添加项
    _GUICtrlListView_BeginUpdate($hListView)
    _GUICtrlListView_AddItem($hListView, "我爱你123" & 1)
    _GUICtrlListView_AddItem($hListView, "123我爱你" & 2)
    _GUICtrlListView_AddItem($hListView, "你爱我abc" & 3)
    For $iI = 4 To 49
        _GUICtrlListView_AddItem($hListView, "你爱我" & $iI)
    Next
    _GUICtrlListView_AddItem($hListView, "Target item")
    For $iI = 51 To 100
        _GUICtrlListView_AddItem($hListView, "Item " & $iI)
    Next
    _GUICtrlListView_EndUpdate($hListView)

    ; 搜索目标项目
    $iI = _GUICtrlListView_FindText($hListView, "你爱我", true)
    MsgBox(4160, "Information", "Target Item Index: " & $iI)
    _GUICtrlListView_EnsureVisible($hListView, $iI)

    ; 循环至用户退出
    Do
    Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>_Main

;如上代码搜“你爱我”,结果索引为2,事实上我用了false,应该是找不到结果。我换成true后,结果索引还是为2
;真搞不懂了
解决如下:
;2014-03-31 修复项目文本包含中文无法完全匹配的BUG by Afan
Func _GUICtrlListView_FindItem($hWnd, $iStart, ByRef $tFindInfo, $sText = '')
        Local $aSR = StringRegExp($sText, '[^\x00-\xff]', 3), $iL = UBound($aSR), $i
        Local $iBuffer = StringLen($sText) + 1 + $iL
        Local $tBuffer = DllStructCreate('char Text[' & $iBuffer & ']')
        Local $pBuffer = DllStructGetPtr($tBuffer)
        For $i = 0 To $iL - 2
                $sText &= ' '
        Next
        DllStructSetData($tBuffer, 'Text', $sText)
        Local $iRet
        If IsHWnd($hWnd) Then
                If _WinAPI_InProcess($hWnd, $_lv_ghLastWnd) Then
                        DllStructSetData($tFindInfo, 'Text', $pBuffer)
                        $iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $tFindInfo, 0, 'wparam', 'struct*')
                Else
                        Local $iFindInfo = DllStructGetSize($tFindInfo)
                        Local $tMemMap
                        Local $pMemory = _MemInit($hWnd, $iFindInfo + $iBuffer, $tMemMap)
                        Local $pText = $pMemory + $iFindInfo
                        DllStructSetData($tFindInfo, 'Text', $pText)
                        _MemWrite($tMemMap, $tFindInfo, $pMemory, $iFindInfo)
                        _MemWrite($tMemMap, $tBuffer, $pText, $iBuffer)
                        $iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $pMemory, 0, 'wparam', 'ptr')
                        _MemFree($tMemMap)
                EndIf
        Else
                DllStructSetData($tFindInfo, 'Text', $pBuffer)
                $iRet = GUICtrlSendMsg($hWnd, $LVM_FINDITEM, $iStart, DllStructGetPtr($tFindInfo))
        EndIf
        Return $iRet
EndFunc   ;==>_GUICtrlListView_FindItem
下载文件直接用即可

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?加入

×
发表于 2014-3-31 13:41:36 | 显示全部楼层
经测试,在参数为 false 或 true  时:
3.3.6.1 均返回 -1,其它如 3.3.7.15、3.3.9.4、3.3.9.21、3.3.10.0、3.3.10.2 均返回 2
 楼主| 发表于 2014-3-31 13:58:31 | 显示全部楼层
回复 2# afan


    A版你好,感谢测试,上例中感觉即便返回2也只对一半,因为true和false是区别全匹配或模糊匹配的选项,上例中,没有任何一项是纯“你爱我"的字符,都加了后辍编号的
发表于 2014-3-31 17:19:18 | 显示全部楼层
楼主这不是坑么??

下面这行你写的就不对:
$iI = _GUICtrlListView_FindText($hListView, "你爱我", true)
第三个参数应该是索引,你竟然写true或false?

改成:
$iI = _GUICtrlListView_FindText($hListView, "你爱我", -1, True)
然后重试!!

还“严重BUG!”,我了个去。。。。



额外要说的是,你这段代码本身书写逻辑BUG也不少,例如先Opt('MustDeclareVars', 1)强制所有变量必须先定义后使用,紧接着$Debug_LV = False就没定义,以及在函数内声明Global类型变量等等。

做程序要严谨,出现问题永远要先怀疑自己!

评分

参与人数 1金钱 +10 收起 理由
txm888 + 10 感谢测试,已解决

查看全部评分

发表于 2014-3-31 17:19:35 | 显示全部楼层
回复 2# afan


    你被坑了,亲,他代码写的就不对,看4楼解释。
 楼主| 发表于 2014-3-31 17:49:37 | 显示全部楼层
回复 4# skyfree


不好意思,S大,首先说声抱歉,也向A版说声抱歉,我粘贴时弄得疏忽了,在自己电脑上测试去测试来,反而让代码弄乱了
这问题我也是在几个月前都遇到过了,当时也是在中文上出了点问题,我想不可能有错,这么多人用,而且我在坛子上搜索这方面的问题,没有一个人发过这样的疑问
于是当时我就临时解决了项目文本不要出现中文的可能

近段时间又在弄个东西,遇到要用这listView控件,且项目文本可能存在中文,于是问题来了,项目文本只要包含中文,全匹配搜索始终都返回-1,以开头模糊匹配,可以成功返回索引
但项目文本以开头相同的字符串是很多的,确定不了哪一项

最终,我就从帮助文档里copy了这段代码,格式上没有改,就专测试搜索的结果,也是我自己大意,让您们耽误时间看代码了,
我现在再上传一个格式正确的代码,上来供您测试下,问题仍然是包含中文的项目文本无法完全匹配搜索出来,返回值为-1
感谢S大,感谢A版!
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>

_Main()

Func _Main()
    GUICreate("ListView Find Text", 400, 300)
    $hListView = GUICtrlCreateListView("", 2, 2, 394, 268)
    GUISetState()

    ; 添加列
    _GUICtrlListView_AddColumn($hListView, "Items", 100)

    ; 添加项
    _GUICtrlListView_BeginUpdate($hListView)
    _GUICtrlListView_AddItem($hListView, "我爱你123" & 1)
    _GUICtrlListView_AddItem($hListView, "123我爱你" & 2)
    _GUICtrlListView_AddItem($hListView, "你爱我abc" & 3)
    For $iI = 4 To 49
        _GUICtrlListView_AddItem($hListView, "你爱我" & $iI)
    Next
    _GUICtrlListView_AddItem($hListView, "Target item")
    For $iI = 51 To 100
        _GUICtrlListView_AddItem($hListView, "Item " & $iI)
    Next
    _GUICtrlListView_EndUpdate($hListView)

    ; 搜索目标项目
    $iI = _GUICtrlListView_FindText($hListView, "你爱我abc3", -1, false)
    MsgBox(4160, "Information", "Target Item Index: " & $iI)
    _GUICtrlListView_EnsureVisible($hListView, $iI)

    ; 循环至用户退出
    Do
        Until GUIGetMsg() = $GUI_EVENT_CLOSE
    GUIDelete()
EndFunc   ;==>_Main
发表于 2014-3-31 18:29:34 | 显示全部楼层
回复  afan


    你被坑了,亲,他代码写的就不对,看4楼解释。
skyfree 发表于 2014-3-31 17:19



    老熟人,没看代码,只帮测试去了,木有想到,还真坑
发表于 2014-3-31 19:17:42 | 显示全部楼层
回复 7# afan


  A大你才真是大“坑”!你的机器竟然能跑那么多个AU3版本!
发表于 2014-3-31 19:25:06 | 显示全部楼层
回复  afan


  A大你才真是大“坑”!你的机器竟然能跑那么多个AU3版本!
user3000 发表于 2014-3-31 19:17



    呵呵,还不止这几个哈 ~
发表于 2014-3-31 19:29:04 | 显示全部楼层
本帖最后由 afan 于 2014-3-31 21:09 编辑

回复 6# txm888


    将 GuiListView.au3 内的原“_GUICtrlListView_FindItem”重命名,用以下替换试试
Func _GUICtrlListView_FindItem($hWnd, $iStart, ByRef $tFindInfo, $sText = '')
        Local $aSR = StringRegExp($sText, '[^\x00-\xff]', 3), $iL = UBound($aSR), $i
        Local $iBuffer = StringLen($sText) + 1 + $iL
        Local $tBuffer = DllStructCreate('char Text[' & $iBuffer & ']')
        Local $pBuffer = DllStructGetPtr($tBuffer)
        For $i = 0 To $iL - 2
                $sText &= ' '
        Next
        DllStructSetData($tBuffer, 'Text', $sText)
        Local $iRet
        If IsHWnd($hWnd) Then
                If _WinAPI_InProcess($hWnd, $_lv_ghLastWnd) Then
                        DllStructSetData($tFindInfo, 'Text', $pBuffer)
                        $iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $tFindInfo, 0, 'wparam', 'struct*')
                Else
                        Local $iFindInfo = DllStructGetSize($tFindInfo)
                        Local $tMemMap
                        Local $pMemory = _MemInit($hWnd, $iFindInfo + $iBuffer, $tMemMap)
                        Local $pText = $pMemory + $iFindInfo
                        DllStructSetData($tFindInfo, 'Text', $pText)
                        _MemWrite($tMemMap, $tFindInfo, $pMemory, $iFindInfo)
                        _MemWrite($tMemMap, $tBuffer, $pText, $iBuffer)
                        $iRet = _SendMessage($hWnd, $LVM_FINDITEM, $iStart, $pMemory, 0, 'wparam', 'ptr')
                        _MemFree($tMemMap)
                EndIf
        Else
                DllStructSetData($tFindInfo, 'Text', $pBuffer)
                $iRet = GUICtrlSendMsg($hWnd, $LVM_FINDITEM, $iStart, DllStructGetPtr($tFindInfo))
        EndIf
        Return $iRet
EndFunc   ;==>_GUICtrlListView_FindItem

评分

参与人数 1金钱 +10 收起 理由
txm888 + 10 A版,谢谢,已修复BUG

查看全部评分

发表于 2014-3-31 19:39:33 | 显示全部楼层
回复 8# user3000


    多个版本没问题的,写个程序自动切换注册表项目就可以的。
发表于 2014-3-31 20:41:53 | 显示全部楼层
回复 10# afan


    看来这个函数还真是有问题,下午在公司测试的时候发现确实有问题~修改这个之后可以了~
发表于 2014-3-31 22:10:39 | 显示全部楼层
回复 11# skyfree

谢谢,还真没想过这么弄一弄的!
 楼主| 发表于 2014-4-1 07:21:08 | 显示全部楼层
回复 10# afan


    才人,解决了我很久以来的困惑,貌似问题一到A版这,就成小儿科了
看了下修改,加了点正则,但不明白意思,惭愧,再次感谢
我将代码和修改的文件发到了1楼,方便其它朋友下载使用。
 楼主| 发表于 2014-4-1 07:21:20 | 显示全部楼层
回复 12# haijie1223


    感谢参与
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-3-29 18:15 , Processed in 0.085559 second(s), 25 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表