Что нового

Аналог DllStructCreate (в связи с медленной работой)

The Dream

Новичок
Сообщения
393
Репутация
3
Пожалуйста, подскажите - есть ли аналог DllStructCreate, так как с помощью структуры работа довольна медленная. Вернее скорость DllStructGetData/DllStructSetData :scratch:
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
The Dream
что нужно сделать? цель кода?
покажи код,который медленно работает?
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
У каждой линии в ListView есть своя структура, в которой параметры item-a (цвет шрифта, фон).

Я создаю структуру и записываю указатель в _GUICtrlListView_SetItemParam.
Потом в общем получаю, и извлекаю нужные мне данные через DllStructGetData что и есть медленным на деле..
 

joiner

Модератор
Локальный модератор
Сообщения
3,557
Репутация
628
то есть ты для хранения данных используешь структуру? по другому никак?
а если использовать просто массивы?
может не в работе со структурами дело,а тормозит в другой части кода?
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Как я понял, структуры совсем не предназначены для ... всего. В основном они для использования в DllCall.

Но как тогда поступить в этом примере, чтобы обойтись без структур:

Код:
Dim $aArray[5]

$aArray[0] = 111
$aArray[1] = 222
$aArray[2] = 333
$aArray[3] = 444
$aArray[4] = 555

; Добавляем

$tBuff1 = DllStructCreate('int['& UBound($aArray) &']')

For $i = 1 To UBound($aArray)
    DllStructSetData($tBuff1, 1, $aArray[$i-1], $i)
Next

MsgBox(64,'Array - > Struct', DllStructGetPtr($tBuff1))

; Извлекаем

$tBuff2 = DllStructCreate('int[5]', DllStructGetPtr($tBuff1))

    MsgBox(64, 'Struct - > Array', DllStructGetData($tBuff2, 1, 4))



Добавлено:
Сообщение автоматически объединено:

joiner, нет, нет, дело именно в структурах к сожалению. Массив никак - строка может удалится, и будет изменения и в массиве (неблагоприятные).
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Это бессмысленный разговор до тех пор, пока не будет полностью ясна логика программы. Тот пример, который я приводил, является наиболее оптимальным для хранения данных элементов ListView, TreeView и др. По такому же принципу работают все программы, например тот же Windows Explorer.

Если целью стоит запись всей этой информации в файл, то, естественно, записывать не нужно побайтно или что-то типа того. Вообщем, к любой задачи нужно подходить с полным пониманием того, что нужно сделать.


Добавлено:
Сообщение автоматически объединено:

The Dream сказал(а):
Но как тогда поступить в этом примере, чтобы обойтись без структур...

Зачем здесь вообще структуры? Что делает этот код? Ты можешь доходчиво описать то, что в результате должно получиться. Подробно! Что будет отображаться в ListView, сколько записей он будет содержать, допускается ли добавление/удаление элементов и т.д. Да и вообще, что в итоге должна выполнять твоя программа? Каждый нюанс может быть важен.


Добавлено:
Сообщение автоматически объединено:

На твой предыдущий вопрос логично ответить так:

Код:
Dim $aArray[5]

$aArray[0] = 111
$aArray[1] = 222
$aArray[2] = 333
$aArray[3] = 444
$aArray[4] = 555

MsgBox(64, 'Array', $aArray[3])


Есть смысл?
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Yashied, скажите, вернее напишите. Не глупо ли использовать (это я не о Вашем примере) для каждого item-a в _GUICtrlListView_Create() - структуру. Ведь это создает большую нагрузку, особенно когда много строк. Так как DllStructGetData - довольно медленно.

Вот пример с использованием структур:

Код:
Func WM_NOTIFY($hWnd, $iMsg, $wParam, $lParam)

	Local $tNMHDR = DllStructCreate($tagNMHDR, $lParam)
	Local $hWndFrom = DllStructGetData($tNMHDR, 'hWndFrom')
	Local $iCode = DllStructGetData($tNMHDR, 'Code')
	Local $sItemText

	Switch $hWndFrom
		Case $hListView
			Switch $iCode

				Case $NM_CUSTOMDRAW

					Local $tNMLVCD = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
					Local $iDrawStage = DllStructGetData($tNMLVCD, 'dwDrawStage')
					Local $iItem = DllStructGetData($tNMLVCD, 'dwItemSpec')
					Local $iSubItem = DllStructGetData($tNMLVCD, 'iSubItem')

					Switch $iDrawStage
						Case $CDDS_PREPAINT
							Return $CDRF_NOTIFYITEMDRAW
						Case $CDDS_ITEMPREPAINT
							Return $CDRF_NOTIFYSUBITEMDRAW
						Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)

							$sItemText = _GUICtrlListView_GetItemText($hWndFrom, $iItem, $iSubItem)

							If _GUICtrlListView_GetItemParam($hWndFrom, $iItem) = 0 Then
								Local $pParam = _WinAPI_CreateBuffer(32)
								Local $tParam = DllStructCreate('int[8]', $pParam)
								For $z = 1 To 8
									DllStructSetData($tParam, 1, 0xFDFFB9, $z)
								Next
								_GUICtrlListView_SetItemParam($hWndFrom,$iItem,$pParam)
							EndIf

							Select
								Case StringInStr($sItemText, 'True')
									 _GUICtrlListView_SetItemText($hWndFrom, $iItem, StringReplace($sItemText,'True',''), $iSubItem)
									$pParam = _GUICtrlListView_GetItemParam($hWndFrom,$iItem)
									$tParam = DllStructCreate('int[8]', $pParam)
									DllStructSetData($tParam, 1,0x95FF9F, $iSubItem+1)

								Case StringInStr($sItemText, 'False')
									 _GUICtrlListView_SetItemText($hWndFrom, $iItem, StringReplace($sItemText,'False',''), $iSubItem)
									$pParam = _GUICtrlListView_GetItemParam($hWndFrom,$iItem)
									$tParam = DllStructCreate('int[8]', $pParam)
									DllStructSetData($tParam, 1,0xFF9595, $iSubItem+1)

								Case StringInStr($sItemText, 'Warning')
									 _GUICtrlListView_SetItemText($hWndFrom, $iItem, StringReplace($sItemText,'Warning',''), $iSubItem)
									$pParam = _GUICtrlListView_GetItemParam($hWndFrom,$iItem)
									$tParam = DllStructCreate('int[8]', $pParam)
									DllStructSetData($tParam, 1,0xFFDD95, $iSubItem+1)

								Case Else
									$pParam = _GUICtrlListView_GetItemParam($hWndFrom,$iItem)
									$tParam = DllStructCreate('int[8]', $pParam)
                                     $iColor = DllStructGetData($tParam, 1, $iSubItem+1)
									  DllStructSetData($tNMLVCD, 'clrTextBk', _BGRColor($iColor))

							EndSelect

							Return $CDRF_NEWFONT
					EndSwitch

			

			EndSwitch
	EndSwitch
	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY





Добавлено:
Сообщение автоматически объединено:

Yashied, мне кажется что Вам станет все ясно теперь (я о WM_NOTIFY)
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
То, что написано в этом примере, говорит о полном непонимании автором того, как работает NM_CUSTOMDRAW. Приведи рабочий пример, чтобы я нажал F5 и все понял. Создай список, добавь несколько разных элементов и т.д.

P.S.

Из этого кода я могу сказать лишь то, что он создает утечку памяти.
 

AZJIO

Меценат
Меценат
Сообщения
2,892
Репутация
1,196
The Dream
Используя _GUICtrlListView_SetItemParam можно записать туда индекс массива. Связь ни как не испортиться. При удалении пункта можно в индекс массива записать -1, но не освобождать массив от удалённых пунктов. При перебирании массива для каких либо целей можно удалить удалённые пункты соответственно переписав связь. Триггер разрешения на чистку массива можно делать при условии удалении например треть от общего количества. Фантазия в ваших руках. От вас требуется создать упрощённый пример сделать замеры времени участков кода. Говорить о просто "медленно" нет смысла, не видя ни кода ни таймингов, ничего кроме слова "медленно".
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
По поводу массива я уже подробно писал все "+" и "-", когда отвечал в другой теме.
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Это полу-черновик, так бы сказать - проверить.

$NM_CUSTOMDRAW - это вроде как событие, может я и ошибаюсь.

Многое что в WM_NOTIFY - можно вынести вне, это я конечно исправлю.

В итоге у нас получится всего лишь:

Код:
Case $NM_CUSTOMDRAW

					Local $tNMLVCD = DllStructCreate($tagNMLVCUSTOMDRAW, $lParam)
					Local $iDrawStage = DllStructGetData($tNMLVCD, 'dwDrawStage')
					Local $iItem = DllStructGetData($tNMLVCD, 'dwItemSpec')
					Local $iSubItem = DllStructGetData($tNMLVCD, 'iSubItem')

					Switch $iDrawStage
						Case $CDDS_PREPAINT
							Return $CDRF_NOTIFYITEMDRAW
						Case $CDDS_ITEMPREPAINT
							Return $CDRF_NOTIFYSUBITEMDRAW
						Case BitOR($CDDS_ITEMPREPAINT, $CDDS_SUBITEM)

									$pParam = _GUICtrlListView_GetItemParam($hWndFrom,$iItem)
									$tParam = DllStructCreate('int[8]', $pParam)
									$iColor = DllStructGetData($tParam, 1, $iSubItem+1)
									DllStructSetData($tNMLVCD, 'clrTextBk', _BGRColor($iColor))


							Return $CDRF_NEWFONT
					EndSwitch


Это тоже - неграмотно совсем?


Добавлено:
Сообщение автоматически объединено:

То есть, все остальные параметры мы задаем во время добавления item/subitem
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
The Dream сказал(а):
Это тоже - неграмотно совсем?

Этот код обеспечивает раскраску элементов ListView в заранее заданные цвета. Что в нем медленно работает?
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Yashied, простите, просто меня немного удивило то, что Вы написали что.. я совсем-совсем не понимаю что в коде.

Проблема оказалось в другом месте, глупо, что я только сейчас понял:

Код:
Case $NM_CLICK ; Sent by a list-view control when the user moves the mouse over an item
					$tInfo = DllStructCreate($tagNMLISTVIEW, $lParam)
					$iSubItem = DllStructGetData($tInfo, "SubItem")
					If $iSubItem <> $iSubItemLast Then
						If $iSubItemLast = 0 Then
							$iWidth = 180
						Else
							$iWidth = 80
						EndIf
						_GUICtrlListView_SetColumnWidth($hListView, $iSubItemLast, $iWidth)
						_GUICtrlListView_SetColumnWidth($hListView, $iSubItem, 180)
						_GUICtrlListView_BeginUpdate($hListView)
						_GUICtrlListView_EndUpdate($hListView)
						$iSubItemLast = $iSubItem
					EndIf


И в итоге. Для такого дела, структуры использовать - лучший выход, верно?
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Да, и нет смысла вызывать _GUICtrlListView_GetItemParam(), т.к. это значение находится в самой структуре $tNMLVCD - "lItemlParam".
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Yashied, спасибо, до этого мое внимание еще не дошло. Извините, если что не так.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Нет, ну мне просто уже интересно стало, в чем заключается медленная работа структур? Тот пример был прямым ответом на вопрос по поводу раскрашивания элементов ListView. Для этой цели да, хранение информации о цвете элемента в структуре является самым оптимальным вариантом. И все должно работать быстро и без нареканий. Что будет дальше происходить с этой информацией я не знаю, поэтому и не могу ничего сказать.
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Хорошо, объясню.

Все дело в том, что раскрашивалось отлично. Но когда я нажимал на колонку (column) - она сразу увеличивалась по ширине, чтобы можно было комфортно просмотреть весь subitem. Но, дело в том, что увеличивалась сразу, а окрашивалась - нет. То есть примерно через пол-секунды, или даже может секунду. Вот тут я и подумал, что это дело в структурах. А оказалось в действиях, которые были "под" $NM_CLICK (GUICtrlListView_SetColumnWidth).

Надеюсь, теперь понятно.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Вот теперь понятно :smile: Кстати, а зачем программировать подобное действие, если можно просто два раза кликнуть на границе колонок? Да, и за клик по заголовку отвечает LVN_COLUMNCLICK (если речь об этом).
 
Автор
T

The Dream

Новичок
Сообщения
393
Репутация
3
Yashied, я так не пробовал, может так лучше. Но не всегда пользователю будет легче прийти к этому действию, все же больше шансов что он просто совершит "клик" по колонке. Плюс - фикс. ширина, чтобы колонка то увеличивалась по ширине, но не "убирала" остальные за горизонт.

OffTopic:
Спасибо Вам за инструкцию по работе _GUICtrlListView_GetItemParam, очень помогла.

Правда искал, как записывать просто данные в память с помощью WinApi, и потом указатель в _GUICtrlListView_GetItemParam, но так и не нашел. Ну, в общем, это наверно уже оффтоп.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
The Dream сказал(а):
Правда искал, как записывать просто данные в память с помощью WinApi, и потом указатель в _GUICtrlListView_GetItemParam, но так и не нашел.

В AutoIt нельзя просто так получить адрес любой переменной, например массива, написав @Array, т.к. все переменные имеют тип Variant. Поэтому приходится создавать свои блоки памяти (структуры) и записывать в них данные. Зачем я написал _WinAPI_CreateBuffer()? Потому что в отличии от структур, она не требует создания переменных, что идеально подходит для подобных задач.
 
Верх