Что нового

Увеличение скорости поиска в ListView

Norm

Продвинутый
Сообщения
269
Репутация
70
Хочу лишь поделится своим небольшим опытом.

В библиотеке UDF GuiListView.au3 есть альтернативнае функци для создания таблиц:
_GUICtrlListView_Create, _GUICtrlListView_AddItem, _GUICtrlListView_AddSubItem
а так же функция _GUICtrlListView_FindInText для поиска пункта содержащего текст в любом месте таблицы.
Случайно заметил, что поиск с помощью нативных функций идет на много быстрее, а так же заметил, тот же эффект в создании таблиц
при помощи нативных GUICtrlCreateListView и GUICtrlCreateListViewItem.
Я решил сделать свою функцию для поиска, а с подачи xXx проверить работу во всх вариантах создания ListView.

После окончательной доработки, просто обалдел.
Скорость поиска во всех вариантах таблиц была намного выше а в "нативных" просто в разы превышает UDF.

FindText.png

В примере ниже этот-же тест со всеми тремя вариантами создания ListView и сравнения поиска в них.
Про скорость создания так же можно немного здесь поситать.

Передаваемые параметры идентичны параметрам из UDF (См. справку для _GUICtrlListView_FindInText )
Если кто-то уже имеет у себя в в скрипте #include <SendMessage.au3>, то имеет смысл использовать _SendMessage вместо __SendMessage
Код:
Func _GUICtrlListView_FindInTextEx($hLtVw, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    If $bReverse And $iStart = -1 Then Return -1
    Local $iId, $iCount, $iColumns, $hWnd = $hLtVw, $iDm[2]
    Local $tItem = DllStructCreate("struct;uint Mask;int Item;int SubItem;uint State;uint StateMask;ptr Text;int TextMax;int Image;lparam Param;" & _
    "int Indent;int GroupID;uint Columns;ptr pColumns;ptr piColFmt;int iGroup;endstruct")
    Local $pItem = DllStructGetPtr($tItem)
    DllStructSetData($tItem, 'Mask', 0x00000004)
    If Not IsHWnd($hLtVw) Then
        $hWnd = GUICtrlGetHandle($hLtVw)
        If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
        DllStructSetData($tItem, "Item", 0)
        GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
        $iId = DllStructGetData($tItem, 'Param')
        If $iId > 0 And GUICtrlGetState($iId) > 0 Then
            $iDm[0] = Opt("GUIDataSeparatorChar")
        EndIf
        $iCount = GUICtrlSendMsg($hLtVw, (0x1000+4), 0, 0)
        $iColumns = HWnd(GUICtrlSendMsg($hLtVw, (0x1000 + 31), 0, 0))
    Else
        $iCount = _SendMessage($hLtVw, (0x1000+4))
        $iColumns = HWnd(_SendMessage($hLtVw, (0x1000+31)))
    EndIf
    $iColumns = _SendMessage($iColumns, 0x1200)
    Local $hWin = DllCall("user32.dll", "hwnd", "GetParent", "hwnd", $hWnd)
    $hWin = $hWin[0]
    If Not $hWin Then Return SetError(2, 0, 0)
    Local $iI, $iJ, $aPrm[3] = [($iStart+1),($iCount-1),1]
    If $bReverse Then Dim $aPrm[3] = [($iStart-1),0,-1]
    If $iDm[0] <> "" Then $iDm[1] = Opt("GUIDataSeparatorChar", "⑀")
    For $iI = $aPrm[0] To $aPrm[1] Step $aPrm[2]
        If $iDm[1] <> "" Then
            DllStructSetData($tItem, 'Item',$iI)
            GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
            If StringInStr(GUICtrlRead(DllStructGetData($tItem, 'Param')), $sText) Then
                Opt("GUIDataSeparatorChar", $iDm[0])
                Return $iI
            EndIf
        Else
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        EndIf
    Next
    If Not ((($iStart = -1) Or Not $bWrapOK) And Not $bReverse) Then
        If $bReverse And $bWrapOK Then
            Dim $aPrm[3] = [($iCount-1),($iStart+1),-1]
        Else
            $aPrm[0] = 0
            $aPrm[1] = $iStart-1
        EndIf
        For $iI = $aPrm[0] To $aPrm[1] Step $aPrm[2]
            If $iDm[1] <> "" Then
                DllStructSetData($tItem, 'Item', $iI)
                GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
                If StringInStr(GUICtrlRead(DllStructGetData($tItem, 'Param')), $sText) Then
                    Opt("GUIDataSeparatorChar", $iDm[0])
                    Return $iI
                EndIf
            Else
                For $iJ = 0 To $iColumns - 1
                    If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
                Next
            EndIf
        Next
    EndIf
    If $iDm[1] <> "" Then Opt("GUIDataSeparatorChar", $iDm[0])
    Return -1
EndFunc

Маленькая напоминалка для создания "нативных" ListView
При заполнении пунктов текстом, в "нативных" ListView, нужно помнить о разделителе (по умолчанию "|")
В примере я намеренно засунул в текст "|" поскольку этот символ иногда тоже может попадаться в тексте.
Код:
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

Global $sFindStr = 'Стр 4999 | Кол 9' ; Строка поиска
$hLVWin = GUICreate('ListView 5000 x 15.   Сравнение создания и поиска строки', 1150, 300)
Local $Header, $aTime[3][5]
For $i = 1 To 25
    $Header &= "Колонка " & $i &"|"
Next
$aTime[0][0] = "Создание ListView"
$aTime[0][1] = "0"
$aTime[1][0] = "Поиск с UDF"
$aTime[1][1] = 0
$aTime[2][0] = "Поиск с Ex"
$aTime[2][1] = 0

Local $hListView = _GUICtrlListView_Create($hLVWin, $Header, 2, 2, 1144, 268)
GUISetState()

GUISetCursor(15, 1)
Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 5000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' | Кол 1')
    For $j = 1 To 15
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' | Кол ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][2] = Ceiling(TimerDiff($hTimer))
GUISetCursor(-1, 1)
MsgBox(262144, Default, "Время создание таблицы 5000x15 (Full UDF): "& $aTime[0][2] & @CRLF & @CRLF & _
"Далее последует сравнение поиска _GUICtrlListView...:"& @CRLF & @CRLF &"1. Функция из UDF -> _FindInText"& @CRLF & @CRLF &"2. Альтернатив. Ex -> _FindInTextEx")
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)
$aTime[1][2] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[1][1] += 1
GUISetCursor(-1, 1)
MsgBox(262144, 'Результат поиска c UDF', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[1][2])
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInTextEx($hListView, $sFindStr)
$aTime[2][2] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[2][1] += 1
GUISetCursor(-1, 1)
MsgBox(262144, 'Результат поиска c Ex', '_GUICtrlListView_FindInTextEx()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[2][2])

GUICtrlDelete($hListView)

Local $hListView = GUICtrlCreateListView($Header, 2, 2, 1144, 268)
GUISetState()
GUISetCursor(15, 1)
Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 5000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' | Кол 1')
    For $j = 1 To 15
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' | Кол ' & ($j + 1), $j)
    Next
    _GUICtrlListView_SetItemParam($hListView, $i, 1000+$i)
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][3] = Ceiling(TimerDiff($hTimer))
GUISetCursor(-1, 1)
MsgBox(262144, Default, "Время создание таблицы 5000x15 (Native + UDF): "& $aTime[0][3] & @CRLF & @CRLF & _
"Далее последует сравнение поиска _GUICtrlListView...:"& @CRLF & @CRLF &"1. Функция из UDF -> _FindInText"& @CRLF & @CRLF &"2. Альтернатив. Ex -> _FindInTextEx")
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)
$aTime[1][3] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[1][1] += 1
GUISetCursor(-1, 1)
MsgBox(262144, 'Результат поиска c UDF', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[1][3])
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInTextEx($hListView, $sFindStr)
$aTime[2][3] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[2][1] += 1
GUISetCursor(-1, 1)
MsgBox(262144, 'Результат поиска c Ex', '_GUICtrlListView_FindInTextEx()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[2][3])

GUICtrlSendMsg($hListView, $LVM_DELETEALLITEMS, 0, 0)

Local $iDl = Opt("GUIDataSeparatorChar")
$hListView = GUICtrlCreateListView($Header, 2, 2, 1144, 268)
Opt("GUIDataSeparatorChar", "□")
GUISetCursor(15, 1)
$hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 5000
    $sListe = ""
    For $j = 1 To 15
        $sListe &= "Стр "& $i & " | Кол "& ($j + 1) &"□"
    Next
    GUICtrlCreateListViewItem($sListe, $hListView)
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][4] = Ceiling(TimerDiff($hTimer))
GUISetCursor(-1, 1)
Opt("GUIDataSeparatorChar", $iDl)
MsgBox(262144, Default, "Время создание таблицы 5000x15 (Full Native): "& $aTime[0][4] & @CRLF & @CRLF & _
"Далее последует сравнение поиска _GUICtrlListView...:"& @CRLF & @CRLF &"1. Функция из UDF -> _FindInText"& @CRLF & @CRLF &"2. Альтернатив. Ex -> _FindInTextEx")
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)
$aTime[1][4] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[1][1] += 1
MsgBox(262144, 'Результат поиска c UDF', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[1][4])
GUISetCursor(15, 1)
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInTextEx($hListView, $sFindStr, 120, False, False)
$aTime[2][4] = Ceiling(TimerDiff($hTimer))
If $iI = -1 Then $aTime[2][1] += 1
GUISetCursor(-1, 1)
MsgBox(262144, 'Результат поиска c Ex', '_GUICtrlListView_FindInTextEx()' & @LF & 'Индекс пункта: ' & $iI & @CRLF & 'Время поиска: '& $aTime[2][4])

_ArrayDisplay($aTime, "Результат", "", 0, Default, "Функция|Error|Full UDF|Native + UDF|Full Native")
Do
       Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()

Func _GUICtrlListView_FindInTextEx($hLtVw, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    If $bReverse And $iStart = -1 Then Return -1
    Local $iId, $iCount, $iColumns, $hWnd = $hLtVw, $iDm[2]
    Local $tItem = DllStructCreate("struct;uint Mask;int Item;int SubItem;uint State;uint StateMask;ptr Text;int TextMax;int Image;lparam Param;" & _
    "int Indent;int GroupID;uint Columns;ptr pColumns;ptr piColFmt;int iGroup;endstruct")
    Local $pItem = DllStructGetPtr($tItem)
    DllStructSetData($tItem, 'Mask', 0x00000004)
    If Not IsHWnd($hLtVw) Then
        $hWnd = GUICtrlGetHandle($hLtVw)
        If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
        DllStructSetData($tItem, "Item", 0)
        GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
        $iId = DllStructGetData($tItem, 'Param')
        If $iId > 0 And GUICtrlGetState($iId) > 0 Then
            $iDm[0] = Opt("GUIDataSeparatorChar")
        EndIf
        $iCount = GUICtrlSendMsg($hLtVw, (0x1000+4), 0, 0)
        $iColumns = HWnd(GUICtrlSendMsg($hLtVw, (0x1000 + 31), 0, 0))
    Else
        $iCount = _SendMessage($hLtVw, (0x1000+4))
        $iColumns = HWnd(_SendMessage($hLtVw, (0x1000+31)))
    EndIf
    $iColumns = _SendMessage($iColumns, 0x1200)
    Local $hWin = DllCall("user32.dll", "hwnd", "GetParent", "hwnd", $hWnd)
    $hWin = $hWin[0]
    If Not $hWin Then Return SetError(2, 0, 0)
    Local $iI, $iJ, $aPrm[3] = [($iStart+1),($iCount-1),1]
    If $bReverse Then Dim $aPrm[3] = [($iStart-1),0,-1]
    If $iDm[0] <> "" Then $iDm[1] = Opt("GUIDataSeparatorChar", "⑀")
    For $iI = $aPrm[0] To $aPrm[1] Step $aPrm[2]
        If $iDm[1] <> "" Then
            DllStructSetData($tItem, 'Item',$iI)
            GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
            If StringInStr(GUICtrlRead(DllStructGetData($tItem, 'Param')), $sText) Then
                Opt("GUIDataSeparatorChar", $iDm[0])
                Return $iI
            EndIf
        Else
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        EndIf
    Next
    If Not ((($iStart = -1) Or Not $bWrapOK) And Not $bReverse) Then
        If $bReverse And $bWrapOK Then
            Dim $aPrm[3] = [($iCount-1),($iStart+1),-1]
        Else
            $aPrm[0] = 0
            $aPrm[1] = $iStart-1
        EndIf
        For $iI = $aPrm[0] To $aPrm[1] Step $aPrm[2]
            If $iDm[1] <> "" Then
                DllStructSetData($tItem, 'Item', $iI)
                GUICtrlSendMsg($hLtVw, (0x1000+75), 0, $pItem)
                If StringInStr(GUICtrlRead(DllStructGetData($tItem, 'Param')), $sText) Then
                    Opt("GUIDataSeparatorChar", $iDm[0])
                    Return $iI
                EndIf
            Else
                For $iJ = 0 To $iColumns - 1
                    If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
                Next
            EndIf
        Next
    EndIf
    If $iDm[1] <> "" Then Opt("GUIDataSeparatorChar", $iDm[0])
    Return -1
EndFunc
Переработал пример предложенный xXx
Кстати ему отдельное спасибо за помощь, точнее подталкивание в нужное направление. :good:
Более наглядный пример и альтернативная реализация того-же принципа от xXx

PS
В библиотеке GuiListView.au3 очень много нужных и незаменимых функций, но вместо некоторых стот пропробовать альтернативу.
 
Последнее редактирование:
  • Like
Реакции: xXx

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
Не работает :nea:
Уже работает
 
Последнее редактирование:
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Спасибо что проверили.
Я предполагал, что без нативных функций исход будет именно такой.
Но с нативном всё прекрасно работает, и создание пунктов происходит намного быстрее. (примерно в два раза)
Однако прирост в скорости поиска (конкретно в Вашем примере) оказался минимальный.
Хотя в моей рабочей таблице прирост увеличивается почти в восемь раз.

Вот сравнение с использованием нативных функций при создании пунктов
Код:
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>

Global $sFindStr = 'Стр 9500 : Кол 9' ; Строка поиска

GUICreate('ListView - Поиск в строке', 1150, 300)
Local $sListe
For $i = 1 To 14
    $sListe &= "Колонка " & $i &"|"
Next
$hListView = GUICtrlCreateListView($sListe, 2, 2, 1144, 268)
GUISetState()

Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' : Кол 1')
    For $j = 1 To 14
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' : Кол ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView)
MsgBox(262144, Default, "Создание таблицы с UDF: "& Ceiling(TimerDiff($hTimer)))

GUICtrlSendMsg($hListView, $LVM_DELETEALLITEMS, 0, 0)

Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    $sListe = ""
    For $j = 1 To 14
        $sListe &= "Стр "& $i & " : Кол "& ($j + 1) &"|"
    Next
    GUICtrlCreateListViewItem($sListe, $hListView)
Next
_GUICtrlListView_EndUpdate($hListView)
MsgBox(262144, Default, "Создание таблицы с натив: "& Ceiling(TimerDiff($hTimer)))


MsgBox(262144, Default, '•••••••••• СТАРТ ••••••••••')

; Поиск пункта назначения
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)

MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска '& Ceiling(TimerDiff($hTimer)))

$hTimer = TimerInit()
$iI = __GUICtrlListView_FindInText_byNorm($hListView, $sFindStr)
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText_byNorm()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска '& Ceiling(TimerDiff($hTimer)))

_GUICtrlListView_EnsureVisible($hListView, $iI)
Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()


Func __GUICtrlListView_FindInText_byNorm($hWnd, $sText)
    Local $iCount = _GUICtrlListView_GetItemCount($hWnd)
    Local $nID
    For $iI = 0 To $iCount - 1
        $nID = _GUICtrlListView_GetItemParam($hWnd, $iI)
        If StringInStr(GUICtrlRead($nID), $sText) Then Return $iI
    Next
    Return -1
EndFunc   ;==>_GUICtrlListView_FindInText
 
Последнее редактирование:

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
... Я предполагал, что без нативных функций исход будет именно такой...
Хм... Странное рассуждение для разработчика.
В вашей функции используется GUICtrlRead(), а ей как известно нужен ID, причем ID сознанный GUI Autoit. Именно по этому ваша функция ничего не сможет найти в ListView созданных по средствам UDF "GuiListView.au3".
А поскольку мы это сейчас выяснили, то вы можете вообще отказаться от UDF и переписать пример (которого до сих пор почему-то нет в шапке) и функцию с использованием только нативных функций и только для нативных ListView.
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <ListViewConstants.au3>

Global $iId, $sListe, $sFindText = 'Стр 5000 : Кол 9' ; Строка поиска

GUICreate('ListView - Поиск', 1150, 300)

For $i = 1 To 14
    $sListe &= 'Колонка ' & $i & '|'
Next
$idListView = GUICtrlCreateListView(StringTrimRight($sListe, 1), 2, 2, 1144, 268)
GUISetState()

GUICtrlSendMsg($idListView, $WM_SETREDRAW, False, 0) ; _GUICtrlListView_BeginUpdate()
For $i = 1 To 5000
    $sListe = ''
    For $j = 1 To 14
        $sListe &= 'Стр ' & $i & ' : Кол ' & $j & '|'
    Next
    $sListe = StringTrimRight($sListe, 1)
    GUICtrlCreateListViewItem($sListe, $idListView)
Next
GUICtrlSendMsg($idListView, $WM_SETREDRAW, True, 0) ; _GUICtrlListView_EndUpdate()

MsgBox(262144, Default, '•••••••••• СТАРТ ••••••••••')

; Поиск строки в пунктах
$iId = _GUICtrlListView_FindText_byNorm($idListView, $sFindText)
GUICtrlSendMsg($idListView, $LVM_ENSUREVISIBLE, @extended, False); _GUICtrlListView_EnsureVisible()

MsgBox(4160, 'Информация', '_GUICtrlListView_FindText_byNorm()' & @LF & 'ID пункта: ' & $iId)

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE

Func _GUICtrlListView_FindText_byNorm($idListView, $sFindText)
    Local $tItem, $iId, $iCount = GUICtrlSendMsg($idListView, $LVM_GETITEMCOUNT, 0, 0) ; _GUICtrlListView_GetItemCount()
    For $i = 0 To $iCount - 1
        $tItem = DllStructCreate('UINT Mask;INT Item;INT[5];PTR;LPARAM Param'); _GUICtrlListView_GetItemParam()
        $tItem.Mask = $LVIF_PARAM
        $tItem.Item = $i
        GUICtrlSendMsg($idListView, $LVM_GETITEMW, 0, DllStructGetPtr($tItem))
        $iId = $tItem.Param
        If StringInStr(GUICtrlRead($iId), $sFindText) Then Return SetError(0, $i, $iId)
    Next
    Return -1
EndFunc   ;==>_GUICtrlListView_FindText_byNorm
 
Последнее редактирование:
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
и переписать пример
Учел Ваше замечание см. ниже.
Если нареканий к новому варианту не будет, то и в шапке код не долго заменить.
Именно по этому ваша функция ничего не сможет найти в ListView созданных по средствам UDF "GuiListView.au3".
Теперь сможет и сделает это тоже быстрее :yes:
Код:
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

Global $sFindStr = 'Стр 9999 : Кол 9' ; Строка поиска

$hFenster = GUICreate('ListView 10000 x 25.   Сравнение создания и поиска строки', 1150, 300)
Local $sListe
For $i = 1 To 25
    $sListe &= "Колонка " & $i &"|"
Next
$hListView = GUICtrlCreateListView($sListe, 2, 2, 1144, 268)
GUISetState()

Local $aTime[2][3]
$aTime[0][0] = "Создание"
$aTime[1][0] = "Поиск"
Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    $sListe = ""
    For $j = 1 To 25
        $sListe &= "Стр "& $i & " : Кол "& ($j + 1) &"|"
    Next
    GUICtrlCreateListViewItem($sListe, $hListView)
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][2] = Ceiling(TimerDiff($hTimer))
MsgBox(262144, Default, "Время создание таблицы 10000x25 с нативными функциями: "& $aTime[0][2])

GUICtrlSendMsg($hListView, $LVM_DELETEALLITEMS, 0, 0)

Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' : Кол 1')
    For $j = 1 To 25
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' : Кол ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][1] = Ceiling(TimerDiff($hTimer))
MsgBox(262144, Default, "Время создание таблицы 10000x25 с UDF: "& $aTime[0][1])

MsgBox(262144, Default, '•••••••••• Сравнение поиска ••••••••••')

; Поиск пункта назначения
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)
$aTime[1][1] = Ceiling(TimerDiff($hTimer))
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска: '& $aTime[1][1])

$hTimer = TimerInit()
$iI = __GUICtrlListView_FindInText_byNorm($hFenster, $hListView, $sFindStr)
$aTime[1][2] = Ceiling(TimerDiff($hTimer))
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText_byNorm()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска: '& $aTime[1][2])

_GUICtrlListView_EnsureVisible($hListView, $iI)

_ArrayDisplay($aTime, "Результат", "", 0, Default, "Функция|UDF|Натив")

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()


Func __GUICtrlListView_FindInText_byNorm($hFnr, $hWnd, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    Local $iCount = GUICtrlSendMsg($hWnd, $LVM_GETITEMCOUNT, 0, 0)
    Local $iColumns = __SendMessage(HWnd(GUICtrlSendMsg($hWnd, (0x1000 + 31), 0, 0)), 0x1200)
    If $bReverse And $iStart = -1 Then Return -1
    Local $nID
    If $bReverse Then
        For $iI = $iStart - 1 To 0 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = $iStart + 1 To $iCount - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    If (($iStart = -1) Or Not $bWrapOK) And Not $bReverse Then Return -1
    If $bReverse And $bWrapOK Then
        For $iI = $iCount - 1 To $iStart + 1 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = 0 To $iStart - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    Return -1
EndFunc

Func __SendMessage($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lresult")
    Local $aResult = DllCall("user32.dll", $sReturnType, "SendMessageW", "hwnd", $hWnd, "uint", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
    If @error Then Return SetError(@error, @extended, "")
    If $iReturn >= 0 And $iReturn <= 4 Then Return $aResult[$iReturn]
    Return $aResult
EndFunc
PS
Думаю имело бы смысл добавить ещё опцию(и) для поиска в отдельном столбце или столбец-начала и столбец-конечный
 
Последнее редактирование:
  • Like
Реакции: xXx

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
... Теперь сможет...
Не совсем...
Код:
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

Global $sFindStr = 'Стр 9999 : Кол 9' ; Строка поиска

$hFenster = GUICreate('ListView 10000 x 25.   Сравнение создания и поиска строки', 1150, 300)
Local $sListe
For $i = 1 To 25
    $sListe &= "Колонка " & $i &"|"
Next
$hListView = _GUICtrlListView_Create($hFenster, $sListe, 2, 2, 1144, 268)
GUISetState()

_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' : Кол 1')
    For $j = 1 To 25
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' : Кол ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView)

MsgBox(262144, Default, '•••••••••• Сравнение поиска ••••••••••')

$hTimer = TimerInit()
$iI = __GUICtrlListView_FindInText_byNorm($hFenster, $hListView, $sFindStr)
$iTime = Ceiling(TimerDiff($hTimer))
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText_byNorm()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска: '& $iTime)

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()


Func __GUICtrlListView_FindInText_byNorm($hFnr, $hWnd, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    Local $iCount = GUICtrlSendMsg($hWnd, $LVM_GETITEMCOUNT, 0, 0)
    Local $iColumns = __SendMessage(HWnd(GUICtrlSendMsg($hWnd, (0x1000 + 31), 0, 0)), 0x1200)
    If $bReverse And $iStart = -1 Then Return -1
    Local $nID
    If $bReverse Then
        For $iI = $iStart - 1 To 0 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = $iStart + 1 To $iCount - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    If (($iStart = -1) Or Not $bWrapOK) And Not $bReverse Then Return -1
    If $bReverse And $bWrapOK Then
        For $iI = $iCount - 1 To $iStart + 1 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = 0 To $iStart - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hFnr, "", $hWnd, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    Return -1
EndFunc

Func __SendMessage($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lresult")
    Local $aResult = DllCall("user32.dll", $sReturnType, "SendMessageW", "hwnd", $hWnd, "uint", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
    If @error Then Return SetError(@error, @extended, "")
    If $iReturn >= 0 And $iReturn <= 4 Then Return $aResult[$iReturn]
    Return $aResult
EndFunc
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Вы правы, пожалуй это единственное ограничение.
Учитывая, что у разработчика GuiListView.au3 в функциях тоже полно всяких ограничений,
можно тоже указать, что применимо только к таблицам созданным при помощи GUICtrlCreateListView
Возможно из этих же соображений, в своих примерах, для создания таблиц он везде использует нативную функцию.

Сто скажите?

Но если делать универсальную, то моно поместить туда поиск из библиотеки с указанием,
что поиск в таблицах созданных при помощи _GUICtrlListView_Create() будет медленнее.
 
Последнее редактирование:

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
... Сто скажите?..
Идея хороша - реализация страдает.
В вашем последнем варианте функции достаточно заменить 2 строки кода и она будет работать для любых случаев.
+ Советую переименовать ее по нормальному, а также изменить имена некоторых переменных.
... Думаю имело бы смысл добавить ещё опцию(и)...
Вы же разработчик - вам решать.
 
Последнее редактирование:
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Идея хороша - реализация страдает. Если вы выкладываете на всеобщее обозрение результат своих трудов, то сначала перепроверьте его 100 раз, протестируйте. Иначе это не "результат", а извините полуфабрикат.
В вашем последнем варианте функции достаточно заменить 2 строки кода и она будет работать для любых случаев.
+ Советую переименовать ее по нормальному, а также изменить имена некоторых переменных.
Вы же разработчик - вам решать.
Спасибо за советы, обязательно учту.
Такой громкой цели я вообще не преследовал, просто решил поделиться своим маленьким открытием.
Но раз уж начал, то хотел бы до конца довести с учетом ваших рекомендаций.
Если хотите, то берите авторство себе, я всё равно ещё не дорос. По сути Вы уже как минимум соавтор.
Ума не приложу какие строки нужно изменить.
Сообщение автоматически объединено:

Хорошо, что Вы сразу не ответили.
Как говорится, Утро вечера мудренее. Через решение этого, я ещё кое что новое выяснил.
Действительно только две строки, но не на две другие. Это меня и сбило с толку.
Второе противоречие, мешавшее мне просто сделать и проверить, мысль о том,
что ControlListView, согласно справки, использует ID-элемента (про дескриптор ни слова).
Сегодня сделал, проверил и очень удивился, что всё работает.
Вот пример, в котором количество передаваемых параметров идентично штатной функции,
что бы не было нужды всегда создавать дополнительную переменную, для окна GUI.
Код:
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

Global $sFindStr = 'Стр 9999 | Кол 9' ; Строка поиска

$hFenster = GUICreate('ListView 10000 x 25.   Сравнение создания и поиска строки', 1150, 300)
Local $sListe, $iDl = Opt("GUIDataSeparatorChar")
Opt("GUIDataSeparatorChar", "□")
For $i = 1 To 25
    $sListe &= "Колонка " & $i &"□"
Next
$hListView = GUICtrlCreateListView($sListe, 2, 2, 1144, 268)
GUISetState()

Local $aTime[2][3]
$aTime[0][0] = "Создание"
$aTime[1][0] = "Поиск"
Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    $sListe = ""
    For $j = 1 To 25
        $sListe &= "Стр "& $i & " | Кол "& ($j + 1) &"□"
    Next
    GUICtrlCreateListViewItem($sListe, $hListView)
Next
Opt("GUIDataSeparatorChar", $iDl)
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][2] = Ceiling(TimerDiff($hTimer))
MsgBox(262144, Default, "Время создание таблицы 10000x25 с нативными функциями: "& $aTime[0][2])

GUICtrlSendMsg($hListView, $LVM_DELETEALLITEMS, 0, 0)

Local $hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView)
For $i = 1 To 10000
    _GUICtrlListView_AddItem($hListView, 'Стр ' & $i & ' | Кол 1')
    For $j = 1 To 25
        _GUICtrlListView_AddSubItem($hListView, ($i - 1), 'Стр ' & $i & ' | Кол ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView)
$aTime[0][1] = Ceiling(TimerDiff($hTimer))
MsgBox(262144, Default, "Время создание таблицы 10000x25 с UDF: "& $aTime[0][1])

MsgBox(262144, Default, '•••••••••• Сравнение поиска ••••••••••')

; Поиск пункта назначения
$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInText($hListView, $sFindStr)
$aTime[1][1] = Ceiling(TimerDiff($hTimer))
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInText()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска: '& $aTime[1][1])

$hTimer = TimerInit()
$iI = _GUICtrlListView_FindInTextEx($hListView, $sFindStr)
$aTime[1][2] = Ceiling(TimerDiff($hTimer))
MsgBox(4160, 'Информация', '_GUICtrlListView_FindInTextEx()' & @LF & 'Индекс пункта назначения: ' & $iI & @CRLF & _
'Время поиска: '& $aTime[1][2])

_GUICtrlListView_EnsureVisible($hListView, $iI)

_ArrayDisplay($aTime, "Результат", "", 0, Default, "Функция|UDF|Натив")

Do
Until GUIGetMsg() = $GUI_EVENT_CLOSE
GUIDelete()


Func _GUICtrlListView_FindInTextEx($hLtVw, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    Local $iCount, $iColumns, $hWnd = $hLtVw
    If Not IsHWnd($hLtVw) Then
        $hWnd = GUICtrlGetHandle($hLtVw)
        If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
    EndIf
    Local $hWin = DllCall("user32.dll", "hwnd", "GetParent", "hwnd", $hWnd)
    $hWin = $hWin[0]
    If Not $hWin Then Return SetError(2, 0, 0)
    If IsHWnd($hLtVw) Then
        $iCount = __SendMessage($hLtVw, (0x1000 + 4))
        $iColumns = HWnd(__SendMessage($hLtVw, (0x1000 + 31)))
    Else
        $iCount = GUICtrlSendMsg($hLtVw, (0x1000 + 4), 0, 0)
        $iColumns = HWnd(GUICtrlSendMsg($hLtVw, (0x1000 + 31), 0, 0))
    EndIf
    $iColumns = __SendMessage($iColumns, 0x1200)
    If $bReverse And $iStart = -1 Then Return -1
    If $bReverse Then
        For $iI = $iStart - 1 To 0 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = $iStart + 1 To $iCount - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    If (($iStart = -1) Or Not $bWrapOK) And Not $bReverse Then Return -1
    If $bReverse And $bWrapOK Then
        For $iI = $iCount - 1 To $iStart + 1 Step -1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    Else
        For $iI = 0 To $iStart - 1
            For $iJ = 0 To $iColumns - 1
                If StringInStr(ControlListView($hWin, "", $hLtVw, "GetText", $iI, $iJ), $sText) Then Return $iI
            Next
        Next
    EndIf
    Return -1
EndFunc

Func __SendMessage($hWnd, $iMsg, $wParam = 0, $lParam = 0, $iReturn = 0, $wParamType = "wparam", $lParamType = "lparam", $sReturnType = "lresult")
    Local $aResult = DllCall("user32.dll", $sReturnType, "SendMessageW", "hwnd", $hWnd, "uint", $iMsg, $wParamType, $wParam, $lParamType, $lParam)
    If @error Then Return SetError(@error, @extended, "")
    If $iReturn >= 0 And $iReturn <= 4 Then Return $aResult[$iReturn]
    Return $aResult
EndFunc
Надеюсь теперь всё доделано :rolleyes:
В шапке всё сделал тоже.
 
Последнее редактирование:

IMStrelcov

CTPEJIbLLOB
Сообщения
253
Репутация
64
Я конечно не всю тему понял, так быстрым взглядом посмотрел последнее сообщение и бросился в глаза вот этот кусочек кода
Код:
If IsHWnd($hWnd) Then
    $iCount = __SendMessage($hWnd, (0x1000 + 4))
Else
    $iCount = GUICtrlSendMsg($hWnd, (0x1000 + 4), 0, 0)
EndIf
If IsHWnd($hWnd) Then
    $iColumns = HWnd(_SendMessage($hWnd, (0x1000 + 31)))
Else
    $iColumns = HWnd(GUICtrlSendMsg($hWnd, (0x1000 + 31), 0, 0))
EndIf

раз такое дело, то может так правильнее
Код:
If IsHWnd($hWnd) Then
    $iCount = __SendMessage($hWnd, (0x1000 + 4))
    $iColumns = HWnd(_SendMessage($hWnd, (0x1000 + 31)))
Else
    $iCount = GUICtrlSendMsg($hWnd, (0x1000 + 4), 0, 0)
    $iColumns = HWnd(GUICtrlSendMsg($hWnd, (0x1000 + 31), 0, 0))
EndIf
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
раз такое дело, то может так правильнее
Спасибо за подсказку, подправил.
Сообщение автоматически объединено:

Думаю теперь довел до ума. Смотрите в шапке темы.
Скорость поиска в "нативных" ListView у меня показала в десять раз выше чем с UTF
findtext-png.4456

Надеюсь будет востребовано.
 
Последнее редактирование:
  • Like
Реакции: xXx

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
Альтернативная реализация этого же принципа.
Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <GuiListView.au3>

Global $sFindText = 'Стр. 2000| Кол. 50' ; Строка поиска
Global $iItems = 2000 ; Количество пунктов в ListView
Global $iSubItems = 50 ; Количество подпунктов в ListView

Global $ik, $sTemp, $sSeparatorChar, $hTimer, $iIndex
Global $iMsg, $hGUI, $idListView_1, $hListView_2, $idEdit_1, $idEdit_2, $idInput, $idButton_1, $idButton_2

#Region ========= GUI: =================================================
$hGUI = GUICreate('Сравнение скорости поиска строки в ListView', 800, 490)
GUICtrlCreateGroup('Список создан при помощи GUICtrlCreateListView... функций:', 5, 10, 390, 436)
GUICtrlSetFont(-1, 9)
GUICtrlCreateGroup('Список создан при помощи _GUICtrlListView_... функций:', 405, 10, 390, 436)
GUICtrlSetFont(-1, 9)

$idEdit_1 = GUICtrlCreateEdit('Подготовка:' & @CRLF, 10, 225, 380, 215, BitOR($WS_VSCROLL, $ES_READONLY, $ES_AUTOVSCROLL))
GUICtrlSetData(-1, @TAB & '- Список заполняется. Ждите...' & @CRLF, 1)
GUICtrlSetBkColor(-1, 0xFFFED8)
$idEdit_2 = GUICtrlCreateEdit('Подготовка:' & @CRLF, 410, 225, 380, 215, BitOR($WS_VSCROLL, $ES_READONLY, $ES_AUTOVSCROLL))
GUICtrlSetData(-1, @TAB & '- Список заполняется. Ждите...' & @CRLF, 1)
GUICtrlSetBkColor(-1, 0xFFFED8)

GUICtrlCreateLabel('Строка поиска:', 60, 460)
$idInput = GUICtrlCreateInput($sFindText, 150, 457, 100, 20)
$idButton_1 = GUICtrlCreateButton('Искать с _GUICtrlListView_FindInText()', 280, 455, 220)
GUICtrlSetState(-1, $GUI_DISABLE)
$idButton_2 = GUICtrlCreateButton('Искать с _GUICtrlListView_FindInText_v2()', 530, 455, 220)
GUICtrlSetState(-1, $GUI_DISABLE)

For $i = 1 To $iSubItems
    $sTemp &= 'Колонка ' & $i & ($i = $iSubItems ? '' : '|')
Next
$idListView_1 = GUICtrlCreateListView($sTemp, 10, 35, 380, 180)
;~ $hListView_2 = _GUICtrlListView_Create($hGUI, $sTemp, 410, 35, 380, 180, -1, BitOR($LVS_EX_FULLROWSELECT, $WS_EX_CLIENTEDGE))
$hListView_2 = GUICtrlCreateListView($sTemp, 410, 35, 380, 180)

GUISetCursor(15, 1)
GUISetState()
#EndRegion ========= GUI: =================================================

; Заполняем $idListView_1
$sSeparatorChar = Opt('GUIDataSeparatorChar', '+')
$hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($idListView_1)
For $i = 1 To $iItems
    $sTemp = 'Стр. ' & $i & '| Кол. 1'
    For $j = 2 To $iSubItems
        $sTemp &= '+Стр. ' & $i & '| Кол. ' & $j
    Next
    GUICtrlCreateListViewItem($sTemp, $idListView_1)
Next
_GUICtrlListView_EndUpdate($idListView_1)
GUICtrlSetData($idEdit_1, @TAB & '- Список заполнен.' & @CRLF & _
        @TAB & @TAB & 'Колич. строк: ' & $iItems & @CRLF & _
        @TAB & @TAB & 'Колич. колонок: ' & $iSubItems & @CRLF & _
        @TAB & @TAB & 'Время заполнения: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)
Opt('GUIDataSeparatorChar', $sSeparatorChar)

; Заполняем $hListView_2
$hTimer = TimerInit()
_GUICtrlListView_BeginUpdate($hListView_2)
For $i = 1 To $iItems
    _GUICtrlListView_AddItem($hListView_2, 'Стр. ' & $i & '| Кол. 1')
    For $j = 1 To $iSubItems
        _GUICtrlListView_AddSubItem($hListView_2, ($i - 1), 'Стр. ' & $i & '| Кол. ' & ($j + 1), $j)
    Next
Next
_GUICtrlListView_EndUpdate($hListView_2)
GUICtrlSetData($idEdit_2, @TAB & '- Список заполнен.' & @CRLF & _
        @TAB & @TAB & 'Колич. строк: ' & $iItems & @CRLF & _
        @TAB & @TAB & 'Колич. колонок: ' & $iSubItems & @CRLF & _
        @TAB & @TAB & 'Время заполнения: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)

$hTimer = 0
GUISetCursor(-1, 1)
GUICtrlSetCursor($idInput, 5)
GUICtrlSetState($idButton_1, $GUI_ENABLE)
GUICtrlSetState($idButton_2, $GUI_ENABLE)

While 1
    $iMsg = GUIGetMsg()
    Switch $iMsg
        Case $GUI_EVENT_CLOSE
            ExitLoop
        Case $idButton_1, $idButton_2
            $sFindText = GUICtrlRead($idInput)
            $ik += 1
            GUISetCursor(15, 1)
            GUICtrlSetState($idButton_1, $GUI_DISABLE)
            GUICtrlSetState($idButton_2, $GUI_DISABLE)
            If $iMsg = $idButton_1 Then
                GUICtrlSetData($idEdit_1, @CRLF & '[' & $ik & '] _GUICtrlListView_FindInText ():' & @CRLF, 1)
                $hTimer = TimerInit()
                $iIndex = _GUICtrlListView_FindInText($idListView_1, $sFindText)
                GUICtrlSetData($idEdit_1, @TAB & @TAB & 'Индекс пункта искомой строки: ' & $iIndex & @CRLF & _
                        @TAB & @TAB & 'Время работы функции: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)

                GUICtrlSetData($idEdit_2, @CRLF & '[' & $ik & '] _GUICtrlListView_FindInText ():' & @CRLF, 1)
                $hTimer = TimerInit()
                $iIndex = _GUICtrlListView_FindInText($hListView_2, $sFindText)
                GUICtrlSetData($idEdit_2, @TAB & @TAB & 'Индекс пункта искомой строки: ' & $iIndex & @CRLF & _
                        @TAB & @TAB & 'Время работы функции: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)
            Else
                GUICtrlSetData($idEdit_1, @CRLF & '[' & $ik & '] _GUICtrlListView_FindInText_v2 ():' & @CRLF, 1)
                $hTimer = TimerInit()
                $iIndex = _GUICtrlListView_FindInText_v2($idListView_1, $sFindText)
                GUICtrlSetData($idEdit_1, @TAB & @TAB & 'ID пункта искомой строки: ' & @extended & @CRLF & _
                        @TAB & @TAB & 'Индекс пункта искомой строки: ' & $iIndex & @CRLF & _
                        @TAB & @TAB & 'Время работы функции: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)

                GUICtrlSetData($idEdit_2, @CRLF & '[' & $ik & '] _GUICtrlListView_FindInText_v2 ():' & @CRLF, 1)
                $hTimer = TimerInit()
                $iIndex = _GUICtrlListView_FindInText_v2($hListView_2, $sFindText)
                GUICtrlSetData($idEdit_2, @TAB & @TAB & 'ID пункта искомой строки: ' & @extended & @CRLF & _
                        @TAB & @TAB & 'Индекс пункта искомой строки: ' & $iIndex & @CRLF & _
                        @TAB & @TAB & 'Время работы функции: ' & Round(TimerDiff($hTimer) / 1000, 3) & ' сек.' & @CRLF, 1)
            EndIf
            GUISetCursor(-1, 1)
            GUICtrlSetCursor($idInput, 5)
            GUICtrlSetState($idButton_1, $GUI_ENABLE)
            GUICtrlSetState($idButton_2, $GUI_ENABLE)
            $hTimer = 0
    EndSwitch
WEnd

#Region ========= FUNCTION: =================================================
Func _GUICtrlListView_FindInText_v2($vListView, $sText, $iStart = -1, $bWrapOK = True, $bReverse = False)
    If $bReverse And $iStart = -1 Then Return -1
    Local $iColumns, $iCount, $tItem, $pItem, $hWnd, $sList, $sSeparatorChar, $iId, $iIndex = -1, $sNewChar = Chr(7)
    Local $aFor[4][3] = [[$iStart - 1, 0, -1], [$iStart + 1, 0, 1], [0, $iStart + 1, -1], [0, $iStart - 1, 1]]
    Local $ia = ($bReverse ? 0 : 1)

    Select
        Case IsInt($vListView) ; Если $vListView является ID, то применяем поиск по элементам Autoit-GUI
            $tItem = DllStructCreate($tagLVITEM)
            $pItem = DllStructGetPtr($tItem)
            DllStructSetData($tItem, 'Mask', $LVIF_PARAM)
            DllStructSetData($tItem, 'Item', 0)
            GUICtrlSendMsg($vListView, $LVM_GETITEMW, 0, $pItem)

            If Not DllStructGetData($tItem, 'Param') Then
                $tItem = 0
                $vListView = GUICtrlGetHandle($vListView)
                ContinueCase ; ListView не имеет Autoit-ControlID -> пробуем поиск по UDF элементам
            EndIf

            $sSeparatorChar = Opt('GUIDataSeparatorChar')
            If StringInStr($sText, $sSeparatorChar) Then
                If Not StringCompare($sSeparatorChar, $sNewChar) Then $sNewChar = Chr(29)
                Opt('GUIDataSeparatorChar', $sNewChar)
            EndIf

            $iCount = GUICtrlSendMsg($vListView, $LVM_GETITEMCOUNT, 0, 0)
            $aFor[1][1] = $iCount - 1
            $aFor[2][0] = $iCount - 1

            For $z = 0 To 1
                For $i = $aFor[$ia][0] To $aFor[$ia][1] Step $aFor[$ia][2]
                    DllStructSetData($tItem, 'Item', $i)
                    GUICtrlSendMsg($vListView, $LVM_GETITEMW, 0, $pItem)
                    $iId = DllStructGetData($tItem, 'Param')
                    If StringInStr(GUICtrlRead($iId), $sText) Then ExitLoop 2
                    $iId = 0
                Next

                If (Not $z And Not $iId) And ((($iStart <> -1) And $bWrapOK) Or $bReverse) Then
                    $ia = ($bReverse And $bWrapOK) ? 2 : 3
                    ContinueLoop
                EndIf
                ExitLoop
            Next

            Opt('GUIDataSeparatorChar', $sSeparatorChar)
            Return SetError(0, $iId, ($iId ? $i : -1))

        Case IsHWnd($vListView); Если $vListView является Handle, то применяем поиск по UDF элементам
            ;Local Const $HDM_GETITEMCOUNT = 0x1200
            $iColumns = _SendMessage(HWnd(_SendMessage($vListView, $LVM_GETHEADER)), 0x1200) ; _GUICtrlListView_GetColumnCount()
            If $iColumns = 0 Then $iColumns = 1

            $hWnd = _WinAPI_GetParent($vListView)
            If $hWnd Then
                $iCount = _SendMessage($vListView, $LVM_GETITEMCOUNT) ; _GUICtrlListView_GetItemCount()
                $aFor[1][1] = $iCount - 1
                $aFor[2][0] = $iCount - 1

                For $z = 0 To 1
                    For $i = $aFor[$ia][0] To $aFor[$ia][1] Step $aFor[$ia][2]
                        For $j = 0 To $iColumns - 1
                            $sList = ControlListView($hWnd, '', $vListView, 'GetText', $i, $j)
                            If StringInStr($sList, $sText) Then
                                $iIndex = $i
                                ExitLoop 3
                            EndIf
                        Next
                    Next

                    If (Not $z And $iIndex = -1) And ((($iStart <> -1) And $bWrapOK) Or $bReverse) Then
                        $ia = ($bReverse And $bWrapOK) ? 2 : 3
                        ContinueLoop
                    EndIf
                    ExitLoop
                Next
            Else; Если не получилось, то воспользуемся стандартным поиском
                $iIndex = _GUICtrlListView_FindInText($vListView, $sText, $iStart, $bWrapOK, $bReverse)
            EndIf

            If $iIndex > -1 Then
                $iId = _SendMessage($vListView, $LVM_MAPINDEXTOID, $iIndex) ; _GUICtrlListView_MapIndexToID()
                Return SetError(0, $iId, $iIndex)
            EndIf
    EndSelect
    Return -1
EndFunc   ;==>_GUICtrlListView_FindInText_v2
#EndRegion ========= FUNCTION: =================================================
 
Последнее редактирование:
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Если заменить это
Код:
$hListView_2 = _GUICtrlListView_Create($hGUI, $sTemp,

на это
Код:
$hListView_2 = GUICtrlCreateListView($sTemp, .....

то перенаправляет в неправильную подфункцию
 
Последнее редактирование:

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
Не уверен что "в тему", но у меня уже с давних пор завалялся вот такой скрипт (виртуальный ListView):

Код:
#include <GUIConstantsEx.au3>
#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <GUIListView.au3>
#include <Array.au3>

Opt('MustDeclareVars', 1)

Global $hGui, $hEdit, $idEditSearch, $hLV, $iItems = 10000, $aItems[$iItems], $aSearch[$iItems], $iSearch = 0

Example()

Func Example()
    ; Create GUI
    $hGui = GUICreate('Virtual ListView search', 300, 230)
    
    ; Create Edit control
    Local $idEdit = GUICtrlCreateEdit('', 10, 10, 300 - 20, 20, BitXOR($GUI_SS_DEFAULT_EDIT, $WS_HSCROLL, $WS_VSCROLL))
    $hEdit = GUICtrlGetHandle($idEdit)
    $idEditSearch = GUICtrlCreateDummy()
    
    ; Handle $WM_COMMAND messages from Edit control
    ; To be able to read the search string dynamically while it's typed in
    GUIRegisterMsg($WM_COMMAND, 'WM_COMMAND')
    
    ; Create ListView
    Local $idLV = GUICtrlCreateListView('', 10, 40, 300 - 20, 200 - 20, $LVS_OWNERDATA, BitOR($WS_EX_CLIENTEDGE, $LVS_EX_DOUBLEBUFFER, $LVS_EX_FULLROWSELECT))
    $hLV = GUICtrlGetHandle($idLV) ;                               Virtual listview                          Reduces flicker
    _GUICtrlListView_AddColumn($hLV, 'Items', 250)
    
    ; Handle $WM_NOTIFY messages from ListView
    ; Necessary to display the rows in a virtual ListView
    GUIRegisterMsg($WM_NOTIFY, 'WM_NOTIFY')
    
    ; Show GUI
    GUISetState(@SW_SHOW)
    
    ; Fill array
    FillArray($aItems, $iItems)
    _ArraySort($aItems, 0, 0, 0, 0, 1)
    
    ; Set search array to include all items
    For $i = 0 To $iItems - 1
        $aSearch[$i] = $i
    Next
    
    $iSearch = $iItems
    
    ; Display items
    GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iSearch, 0)
    
    ; Message loop
    While 1
        Switch GUIGetMsg()
            Case $idEditSearch
                Local $sSearch = GUICtrlRead($idEdit)
                
                If $sSearch = '' Then
                    ; Empty search string, display all rows
                    For $i = 0 To $iItems - 1
                        $aSearch[$i] = $i
                    Next
                    
                    $iSearch = $iItems
                Else
                    ; Find rows matching the search string
                    $iSearch = 0
                    
                    For $i = 0 To $iItems - 1
                        ;If StringInStr( $aItems[$i], $sSearch ) Then ; Normal search
                        If StringRegExp($aItems[$i], $sSearch) Then ; Reg. exp. search
                            $aSearch[$iSearch] = $i
                            $iSearch += 1
                        EndIf
                    Next
                EndIf
                
                GUICtrlSendMsg($idLV, $LVM_SETITEMCOUNT, $iSearch, 0)
                ConsoleWrite(StringFormat('%4d', $iSearch) & ' rows matching ''' & $sSearch & '''' & @CRLF)
            Case $GUI_EVENT_CLOSE
                ExitLoop
        EndSwitch
    WEnd
    
    GUIDelete()
EndFunc

Func FillArray(ByRef $aItems, $iRows)
    Local $aLetters[26] = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', _
            'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
    
    Local $s
    
    For $i = 0 To $iRows - 1
        $s = $aLetters[Random(0, 25, 1)]
        
        For $j = 1 To Random(10, 30, 1)
            $s &= $aLetters[Random(0, 25, 1)]
        Next
        
        $aItems[$i] = $s
    Next
EndFunc

Func WM_COMMAND($hWnd, $iMsg, $wParam, $lParam)
    Local $hWndFrom = $lParam
    Local $iCode = BitShift($wParam, 16) ; High word
    
    Switch $hWndFrom
        Case $hEdit
            Switch $iCode
                Case $EN_CHANGE
                    GUICtrlSendToDummy($idEditSearch)
            EndSwitch
    EndSwitch
    
    Return $GUI_RUNDEFMSG
EndFunc

Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)
    Local Static $tText = DllStructCreate('wchar[50]')
    Local Static $pText = DllStructGetPtr($tText)
    
    Local $tNMHDR, $hWndFrom, $iCode
    $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, 'hWndFrom'))
    $iCode = DllStructGetData($tNMHDR, 'Code')
    
    Switch $hWndFrom
        Case $hLV
            Switch $iCode
                Case $LVN_GETDISPINFOW
                    Local $tNMLVDISPINFO = DllStructCreate($tagNMLVDISPINFO, $lParam)
                    
                    If BitAND(DllStructGetData($tNMLVDISPINFO, 'Mask'), $LVIF_TEXT) Then
                        Local $sItem = $aItems[$aSearch[DllStructGetData($tNMLVDISPINFO, 'Item')]]
                        DllStructSetData($tText, 1, $sItem)
                        DllStructSetData($tNMLVDISPINFO, 'Text', $pText)
                        DllStructSetData($tNMLVDISPINFO, 'TextMax', StringLen($sItem))
                    EndIf
            EndSwitch
    EndSwitch
    
    Return $GUI_RUNDEFMSG
EndFunc


Скорость обработки данных в нём в разы превышает ту скорость что есть при использований обычного LV.
Думаю не составит труда использовать это в целях поиска.

А вообще, если планируется возможность поиска в списке, то я бы изначально заполнял данные в массив или даже в словарь (Dictionary) (и редактировал его при необходимости), и уже искал бы непосредственно в нём, что естественно значительно увеличивает скорость.
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
А вообще, если планируется возможность поиска в списке, то я бы изначально заполнял данные в массив или даже в словарь (Dictionary)
Так и делаем, но это для маленьких и средних таблиц, чтобы с массивами тоже не возиться.
 

CreatoR

Must AutoIt!
Команда форума
Администратор
Сообщения
8,671
Репутация
2,481
чтобы с массивами тоже не возиться
А что с ними возиться, нужно просто создать обёртки (Wrapper) для функции создания и обработки пунктов списка, там уже всё на автомате будет происходить.
 
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
просто создать обёртки (Wrapper) для функции создания и обработки пунктов списка, там уже всё на автомате будет происходить.
Есть ли у Вас какой-то пример с этим? Я такое пока нигде не встречал. Забил в Яндех тоже ничего.

Естественно, ведь GUICtrlCreateListView() возвращает ID а не дескриптор.
Это я это из условия сам понял.
Я надеялся, что может Вы предложите более грамотное решение этого, чем моё
Код:
$iId = _GUICtrlListView_GetItemParam($hLtVw, $tItem, 0)
If $iId > 0 And GUICtrlGetState($iId) > 0 Then
 
Последнее редактирование:

xXx

╚{■_■}╗
Меценат
Сообщения
248
Репутация
95
... Я надеялся, что может Вы предложите более...
Переделал все нафиг.:wink:

У меня примерно также.
Сообщение автоматически объединено:

А что с ними возиться,
Есть ли у Вас какой-то пример с этим?
Господа, а может поделимся опытом во вновь какой-нибудь созданной теме?
 
Последнее редактирование:
  • Like
Реакции: Norm
Автор
N

Norm

Продвинутый
Сообщения
269
Репутация
70
Так выглядит намного лучше.:good:
:blush: Но там в одном условии что, то не так, потому что если подставить параметры, например , 120, False, True , то по идее должно вернуться -1,
поскольку искомой строки там нет.
Ваш вариант и пример уже разместил (в виде ссылки) в шапке темы.
Я всё-же хотел бы ещё не много в про код спросить, что бы не создавать, из за этого новую тему.
Уже не первый раз встречаю такую конструкцию
Код:
Local $ia = ($bReverse ? 0 : 1)
; или
Local[/URL] $iMsg = ($idListView, $LVM_GETUNICODEFORMAT, 0, 0)   ?   $LVM_GETITEMW  :  $LVM_GETITEMA

? n : n В справке ничего не видел такого, или плохо смотрел. Подскажите где об этом прочесть можно.
 
Последнее редактирование:
  • Like
Реакции: xXx
Верх