Что нового

[Данные, строки] Выгрузка данных из _GUICtrlListView в 2D массив и загрузка обратно

kodan76

Новичок
Сообщения
1
Репутация
0
Подскажите, пожалуйста, как выгрузить данные из _GUICtrlListView в 2D массив и загрузка обратно. _GUICtrlListView содержит 2 колонки.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
kodan76,
Попробуйте так.
Код:
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

$iItems = Random(9000, 10000, 1)
$iRows = Random(3, 6, 1)
Dim $aItems[$iItems][$iRows]
For $i = 0 To UBound($aItems) - 1 ;или $iItems - 1
	For $j = 0 To UBound($aItems, 2) - 1 ;или $iRows - 1
		$aItems[$i][$j] = 'Item ' & $i + 1 & '-' & $j
	Next
Next

GUICreate($iItems & 'x' & $iRows, 400, 320)
$nListView = GUICtrlCreateListView('', 2, 2, 394, 268)
$hListView = GUICtrlGetHandle($nListView)
$nButton = GUICtrlCreateButton('Получить', 150, 280, 100, 30)
GUISetState()
For $i = 0 To $iRows - 1
	_GUICtrlListView_AddColumn($hListView, 'SubItems ' & $i, 100)
Next
_GUICtrlListView_AddArray($hListView, $aItems)
$aItems = 0
$iItems = 0
$iRows = 0
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $nButton
			$iStart = TimerInit()
			$iItems = _GUICtrlListView_GetItemCount($hListView)
			$iRows = _GUICtrlListView_GetColumnCount($hListView)
			Dim $aItems[$iItems][$iRows]
			For $i = 0 To $iItems - 1
				For $j = 0 To $iRows - 1
					$aItems[$i][$j] = _GUICtrlListView_GetItemText($hListView, $i, $j)
				Next
			Next
			$sTime = StringFormat('%.2f msec', TimerDiff($iStart))
			_GUICtrlListView_DeleteAllItems($hListView)
			_ArrayDisplay($aItems, $sTime)
			For $i = 0 To UBound($aItems) - 1
				For $j = 0 To UBound($aItems, 2) - 1
					$aItems[$i][$j] &= ' - New'
				Next
			Next
			_GUICtrlListView_AddArray($hListView, $aItems)
			$sTime = ''
			$aItems = 0
			$iItems = 0
			$iRows = 0
	EndSwitch
WEnd
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Я бы посоветовал в данном случае отказаться от _GUICtrlListView... функций в пользу нативной GUICtrlCreateListViewItem(). В этом случае можно достичь максимальной скорости получения данных из списка.

Код:
$Count = 10000

$LV = GUICtrlCreateListView(...)
For $i = 1 To $Count
	GUICtrlCreateListViewItem(..., $LV)
Next

...

$sData = ''
For $i = $LV + 1 To $LV + $Count
	$sData &= GUICtrlRead($i) & ChrW(160)
Next
$aData = StringSplit(StringTrimRight($sData, 1), Chr(160), 2)
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied,
Да, разница во времени большая. Так значительно быстрее.
Код:
#include <GuiConstantsEx.au3>
#include <Array.au3>

$sText = ''
$iItems = Random(9000, 10000, 1)
$iRows = Random(3, 6, 1)
Dim $aItems[$iItems]
For $i = 0 To $iItems - 1
	$sText = ''
	For $j = 0 To $iRows - 1
		$sText &= 'Item ' & $i + 1 & '-' & $j & '|'
	Next
	$aItems[$i] = StringTrimRight($sText, 1)
Next
$hGui = GUICreate($iItems & 'x' & $iRows, 400, 320)
$sText = ''
For $i = 0 To $iRows - 1
	$sText &= 'SubItems ' & $i & '|'
Next
$nListView = GUICtrlCreateListView($sText, 2, 2, 394, 268)
For $i = 1 To $iItems
	GUICtrlCreateListViewItem($aItems[$i - 1], $nListView)
Next
$nButton = GUICtrlCreateButton('Получить', 150, 280, 100, 30)
GUISetState()
$sText = ''
$iItems = 0
$iRows = 0
$aItems = 0
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $nButton
			$iStart = TimerInit()
			$iItems = GUICtrlSendMsg($nListView, 0x1004, 0, 0) ;$LVM_GETITEMCOUNT
			$iRows = ControlListView($hGui, '', $nListView, 'GetSubItemCount')
			ConsoleWrite($iItems & 'x' & $iRows & @LF)
			Dim $aItems[$iItems][$iRows]
			For $i = $nListView + 1 To $nListView + $iItems
				$sText = GUICtrlRead($i)
				$aTemp = StringSplit($sText, '|')
				For $j = 1 To $aTemp[0] - 1
					$aItems[$i - $nListView - 1][$j - 1] = $aTemp[$j]
				Next
			Next
			$sTime = StringFormat('%.2f msec', TimerDiff($iStart))
			_ArrayDisplay($aItems, $sTime)
			$sTime = ''
			$sText = ''
			$iItems = 0
			$iRows = 0
			$aItems = 0
	EndSwitch
WEnd
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Да, но я еще имел в виду не перелопачивать массив в 2D, а изменить алгоритм для использования строк вида "SubItem1|SubItem2|...". Самая мега быстрая функция в AutoIt - StringSplit(), вот под нее и нужно подстраиваться. А еще, madmasles, в вашем примере самое узкое место - _GUICtrlListView_GetItemText(), т.к. при каждом ее вызове создается и удаляется структура "wchar[...]", это самая медленная операция здесь. Если создать структуру один раз перед циклом и перейти на DllCall() - SendMessage(), то можно увеличить скорость в 2-3 раза.

А вообще, зачем нужен 2D массив? Пусть будет 1D массив вида:

[0] - "SubItem1|SubItem2|..."
[1] - "SubItem1|SubItem2|..."
...
[n] - "SubItem1|SubItem2|..."

При необходимости всегда можно извлечь значения "SubItem", это не в пример будет быстрее, чем сразу создавать 2D массив.
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,322
Yashied [?]
зачем нужен 2D массив?
Это к автору темы. :smile:
Если создать структуру один раз перед циклом и перейти на DllCall() - SendMessage(), то можно увеличить скорость в 2-3 раза
Не знаю насколько правильно, но так у меня работает быстрее всего.
Код:
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
#include <Array.au3>

$iItems = 10000;Random(9000, 10000, 1)
$iRows = 3;Random(3, 6, 1)
Dim $aItems[$iItems][$iRows]
For $i = 0 To UBound($aItems) - 1 ;или $iItems - 1
	For $j = 0 To UBound($aItems, 2) - 1 ;или $iRows - 1
		$aItems[$i][$j] = 'Item ' & $i + 1 & '-' & $j
	Next
Next

GUICreate($iItems & 'x' & $iRows, 400, 320)
$nListView = GUICtrlCreateListView('', 2, 2, 394, 268)
$nButton = GUICtrlCreateButton('Получить', 150, 280, 100, 30)
GUISetState()
$iStart = TimerInit()
For $i = 0 To $iRows - 1
	_GUICtrlListView_AddColumn($nListView, 'SubItems ' & $i, 100)
Next
_GUICtrlListView_AddArray($nListView, $aItems)
ConsoleWrite(StringFormat('%.2f msec', TimerDiff($iStart)) & @LF)
$aItems = 0
$iItems = 0
$iRows = 0
While 1
	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $nButton
			$iStart = TimerInit()
			_GUICtrlListView_BeginUpdate($nListView)
			$iItems = _GUICtrlListView_GetItemCount($nListView)
			$iRows = _GUICtrlListView_GetColumnCount($nListView)
			Dim $aItems[$iItems][$iRows]
			$fUnicode = _GUICtrlListView_GetUnicodeFormat($nListView)
			If $fUnicode Then
				$tBuffer = DllStructCreate('wchar Text[4096]')
			Else
				$tBuffer = DllStructCreate('char Text[4096]')
			EndIf
			$pBuffer = DllStructGetPtr($tBuffer)
			$tItem = DllStructCreate($tagLVITEM)
			$pItem = DllStructGetPtr($tItem)
			DllStructSetData($tItem, 'TextMax', 4096)
			DllStructSetData($tItem, 'Text', $pBuffer)
			For $i = 0 To $iItems - 1
				For $j = 0 To $iRows - 1
					DllStructSetData($tItem, 'SubItem', $j)
					If $fUnicode Then
						GUICtrlSendMsg($nListView, $LVM_GETITEMTEXTW, $i, $pItem)
					Else
						GUICtrlSendMsg($nListView, $LVM_GETITEMTEXTA, $i, $pItem)
					EndIf
					$aItems[$i][$j] = DllStructGetData($tBuffer, 'Text')
				Next
			Next
			_GUICtrlListView_EndUpdate($nListView)
			$sTime = StringFormat('%.2f msec', TimerDiff($iStart))
			_ArrayDisplay($aItems, $sTime)
			$sTime = ''
			$aItems = 0
			$iItems = 0
			$iRows = 0
			$fUnicode = 0
			$tBuffer = 0
			$pBuffer = 0
			$tItem = 0
			$pItem = 0
	EndSwitch
WEnd
Добавил _GUICtrlListView_BeginUpdate() и _GUICtrlListView_EndUpdate().
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Браво!

Именно это я и имел ввиду.

:ok:

P.S

Последний штрих - _GUICtrlListView_BeginUpdate() и _GUICtrlListView_EndUpdate().

:smile:
 
Верх