musicstashall
Знающий
- Сообщения
- 322
- Репутация
- 7
- Версия AutoIt
- 3.3.14.2
- Версия
- 3.0
Представляю модификацию стандартной функции просмотра массивов
Вообще, всякий раз, открывая массив для обозрения, я наблюдал неформатированные строки, как на этом скриншоте:
Поэтому я первым делом решил установить шрифт для ListView, в результате видим совсем иную картину:
Плюс к этому я добавил в стиль ListView двойную буферизацию
Но самое главное в другом. Кто часто пользуется массивами, тот понимает, насколько бесполезной становится эта функция, если в массиве содержатся другие массивы, и вы не можете посмотреть содержимое ячейки, содержащей массив:
Я решил исправить такое упущение и теперь вы можете вызвать для просмотра содержимое ячейки с дочерним массивом двойным кликом мыши:
Мне самому очень нужно было видеть содержимое дочерних массивов и я решил это реализовать.
Реализованы нюансы, например, чтобы повторно не открывался массив, если уже открыт, вместо этого, окно с этим массивом будет активировано. После закрытия окна с массивом, данные об этом окне удаляются из переменой и массив можно снова открыть. Все глобальные переменные «виртуальные», создаются функцией
ПС: функции чтения и преобразования строк ( из опорных переменных $sid) сделаны на скорую руку, вероятно, можно будет доработать и сделать более красиво.
Сделал новую версию. Отказался от использования
Добавил получение индекса массива не по индексу пункта ListView а по тексту в пункте, чтобы избежать неверного чтения, если пункты были отсортированы.
Изменения в оригинальном коде:
Добавленные функции:
Готовые файлы для замены оригинальных в папке AutoIt3\include:
_ArrayDisplay
Вообще, всякий раз, открывая массив для обозрения, я наблюдал неформатированные строки, как на этом скриншоте:

Поэтому я первым делом решил установить шрифт для ListView, в результате видим совсем иную картину:

Плюс к этому я добавил в стиль ListView двойную буферизацию
$LVS_EX_DOUBLEBUFFER
, так стало мягче скроллиться, без мерцания.Но самое главное в другом. Кто часто пользуется массивами, тот понимает, насколько бесполезной становится эта функция, если в массиве содержатся другие массивы, и вы не можете посмотреть содержимое ячейки, содержащей массив:

Я решил исправить такое упущение и теперь вы можете вызвать для просмотра содержимое ячейки с дочерним массивом двойным кликом мыши:

Мне самому очень нужно было видеть содержимое дочерних массивов и я решил это реализовать.
Реализованы нюансы, например, чтобы повторно не открывался массив, если уже открыт, вместо этого, окно с этим массивом будет активировано. После закрытия окна с массивом, данные об этом окне удаляются из переменой и массив можно снова открыть. Все глобальные переменные «виртуальные», создаются функцией
Assign
и читаются функцией Eval
, чтобы не засорять исходный скрипт. В функцию _ArrayDisplay добавлен восьмой параметр для родительского окна, чтобы открываемые окна с массивами сохраняли Z-порядок.ПС: функции чтения и преобразования строк ( из опорных переменных $sid) сделаны на скорую руку, вероятно, можно будет доработать и сделать более красиво.
Сообщение автоматически объединено:
Сделал новую версию. Отказался от использования
GUIRegisterMsg($WM_NOTIFY, "WM_ARRAYDISPLAY_NOTIFY")
, так как это отменяло бы предыдущую подобную регистрацию функции у пользователя. Вместо этого использовал глобальные хуки с помощью DllCallbackRegister("CALL_NOTIFY", "int", "hwnd;uint;wparam;lparam")
. Далее, в предыдущем варианте каждое дочернее окно после создания «крутилось» в своем цикле, а потому при закрытии окон, всегда закрывалось только последнее открытое. Поэтому, после создания любого дочернего окна, теперь делается выход из функции перед циклом, то есть, в цикле «крутится» только родительское окно.Добавил получение индекса массива не по индексу пункта ListView а по тексту в пункте, чтобы избежать неверного чтения, если пункты были отсортированы.
Изменения в оригинальном коде:
Код:
#include "StructureConstants.au3" ; Added to the beginning of the script
Func __ArrayDisplay_Share(Const ByRef $aArray, $sTitle = Default, $sArrayRange = Default, $iFlags = Default, $vUser_Separator = Default, $sHeader = Default, $iMax_ColWidth = Default, $hUser_Function = Default, $bDebug = True, $iParent = 0)
;=============== ADD MODIFICATION =============
If __ArrayDisplay_CallBackRegisrer($hGUI, $iParent, $aArray) Then Return
;=============== END MODIFICATION =============
; Switch to GetMessage mode
Local $iOnEventMode = Opt("GUIOnEventMode", 0), $iMsg
While 1
$iMsg = GUIGetMsg() ; Variable needed to check which "Copy" button was pressed
Switch $iMsg
Case $_ARRAYCONSTANT_GUI_EVENT_CLOSE
;================ MODIFICATION ================
Local $hWnd = WinGetHandle('')
Local $hPrnt = __ArrayDisplay_CallBackFree($hWnd)
If Eval($hGUI) Then
__ArrayDisplay_DelhWnd($hWnd, $hPrnt)
Else
ExitLoop
EndIf
;=============== END MODIFICATION =============
WEnd
EndFunc ;==>__ArrayDisplay_Share
Добавленные функции:
Код:
#Region Modification functions
Func CALL_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
Local $aHandle_Proc = Eval('arraydisplayprocdata')
Switch $iMsg
Case 0x4E ; WM_NOTIFY
Local $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
Local $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
Local $idListView = DllStructGetData($tNMHDR, "IDFrom")
Local $iCode = DllStructGetData($tNMHDR, "Code")
Switch $iCode
Case -3 ; NM_DBLCLK
; _WinAPI_GetMousePos
Local $iMode = Opt("MouseCoordMode", 1)
Local $aPos = MouseGetPos()
Opt("MouseCoordMode", $iMode)
Local $tPoint = DllStructCreate($tagPOINT)
DllStructSetData($tPoint, "X", $aPos[0])
DllStructSetData($tPoint, "Y", $aPos[1])
DllCall("user32.dll", "bool", "ScreenToClient", "hwnd", $hWndFrom, "struct*", $tPoint)
If @error Then Return
Local $tTest = DllStructCreate($tagLVHITTESTINFO)
DllStructSetData($tTest, "X", DllStructGetData($tPoint, "X"))
DllStructSetData($tTest, "Y", DllStructGetData($tPoint, "Y"))
; _GUICtrlListView_SubItemHitTest($hWnd)
GUICtrlSendMsg($idListView, 0x00001039, 0, DllStructGetPtr($tTest))
; _GUICtrlListView_GetItemText
Local $tBuffer = DllStructCreate("char Text[4096]")
Local $pBuffer = DllStructGetPtr($tBuffer)
Local $tItem = DllStructCreate($tagLVITEM)
DllStructSetData($tItem, "SubItem", 0)
DllStructSetData($tItem, "TextMax", 4096)
Local $pItem = DllStructGetPtr($tItem)
DllStructSetData($tItem, "Text", $pBuffer)
GUICtrlSendMsg($idListView, 0x1000 + 45, DllStructGetData($tTest, "Item"), $pItem)
Local $iItem = Int(StringReplace(DllStructGetData($tBuffer, "Text"), 'Row ', ''))
If $iItem < 0 Or DllStructGetData($tTest, "SubItem") < 1 Then Return
Local $iIndex = _ArraySearch($aHandle_Proc, $hWnd, 1, 0, 0, 0, 1, 0)
Local $aArray = $aHandle_Proc[$iIndex][5]
If UBound($aArray) < $iItem + 1 Then Return
Local $sid = Eval($hWnd)
Local $sCaption = 'Array[' & $iItem & ']'
Switch UBound($aArray, 0)
Case 1
If Not IsArray($aArray[$iItem]) Then Return
If __ArrayDisplay_IsOpen($sid, $sCaption) Then Return WinActivate(HWnd(__ArrayDisplay_GethWnd($sid, $sCaption)))
Assign($hWnd, $sid ? $sid & '|' & $sCaption : $sCaption, 2) ; We write the cell of the opened array Array[n][n] to the string
__ArrayDisplay_Share($aArray[$iItem], $sCaption, Default, Default, Default, Default, Default, 0, False, $hWnd)
Case 2
If Not IsArray($aArray[$iItem][DllStructGetData($tTest, "SubItem") -1]) Then Return
$sCaption &= '[' & DllStructGetData($tTest, "SubItem") -1 & ']'
If __ArrayDisplay_IsOpen($sid, $sCaption) Then Return WinActivate(HWnd(__ArrayDisplay_GethWnd($sid, $sCaption)))
Assign($hWnd, $sid ? $sid & '|' & $sCaption : $sCaption, 2) ; We write the cell of the opened array Array[n][n] to the string
__ArrayDisplay_Share($aArray[$iItem][DllStructGetData($tTest, "SubItem") -1], $sCaption, Default, Default, Default, Default, Default, 0, False, $hWnd)
EndSwitch
Case -108
__ArrayDisplay_SortItems($idListView, GUICtrlGetState($idListView))
EndSwitch
EndSwitch
For $i = 1 To $aHandle_Proc[0][0]
; And pass other messages to original WindowProc
If $hWnd = $aHandle_Proc[$i][0] Then Return __ArrayDisplay_CallWindowProc($aHandle_Proc[$i][1], $hWnd, $iMsg, $iwParam, $ilParam)
Next
EndFunc
; _WinAPI_CallWindowProc
Func __ArrayDisplay_CallWindowProc($pPrevWndFunc, $hWnd, $iMsg, $wParam, $lParam)
Local $aResult = DllCall("user32.dll", "lresult", "CallWindowProc", "ptr", $pPrevWndFunc, "hwnd", $hWnd, "uint", $iMsg, _
"wparam", $wParam, "lparam", $lParam)
If @error Then Return SetError(@error, @extended, -1)
Return $aResult[0]
EndFunc ;==>_WinAPI_CallWindowProc
; Registering the callback function
Func __ArrayDisplay_CallBackRegisrer($hWnd, $iParent, $aArray)
If Not Eval($iParent) Then
; The very first window is opened, which will be the parent for all subsequent windows.
; All child windows don't come here anymore
Local $aHandle_Proc[1][6] = [[0]]
Assign('arraydisplayprocdata', $aHandle_Proc, 2) ; This is a global variable in which our array with data will be stored
EndIf
Local $aHandle_Proc = Eval('arraydisplayprocdata') ; get our array from the variable
; then a callback is registered and data is written to the array
$aHandle_Proc[0][0] += 1
ReDim $aHandle_Proc[$aHandle_Proc[0][0] + 1][6]
$aHandle_Proc[$aHandle_Proc[0][0]][0] = $hWnd
$aHandle_Proc[$aHandle_Proc[0][0]][2] = DllCallbackRegister("CALL_NOTIFY", "int", "hwnd;uint;wparam;lparam")
$aHandle_Proc[$aHandle_Proc[0][0]][3] = DllCallbackGetPtr($aHandle_Proc[$aHandle_Proc[0][0]][2])
$aHandle_Proc[$aHandle_Proc[0][0]][4] = $iParent
$aHandle_Proc[$aHandle_Proc[0][0]][5] = $aArray
Local $sFuncName = "SetWindowLongW"
If @AutoItX64 Then $sFuncName = "SetWindowLongPtrW"
Local $aResult = DllCall("user32.dll", "long_ptr", $sFuncName, "hwnd", $hWnd, "int", -4, "long_ptr", $aHandle_Proc[$aHandle_Proc[0][0]][3])
If @error Then $aResult = 0
If Not @error Then $aResult = $aResult[0]
$aHandle_Proc[$aHandle_Proc[0][0]][1] = $aResult
If $aHandle_Proc[$aHandle_Proc[0][0]][1] = 0 Then $aHandle_Proc[0][0] -= 1
ReDim $aHandle_Proc[$aHandle_Proc[0][0] + 1][6]
; Put the modified array back into the global variable
Assign('arraydisplayprocdata', $aHandle_Proc, 2)
If Eval($iParent) Then
; Here we write all the child windows to be opened in one line in this way Array[n][n];0x0000000000,
; where Array is the opened array cell in the parent window, after the semicolon is the hWnd of the parent window
; Write the string to a global variable named hWnd of the parent window
Assign($iParent, Eval($iParent) & ';' & $hWnd, 2)
;ConsoleWrite('+' & $iParent & @TAB & 'SID' & @TAB & Eval($iParent) & @CR)
Return $hWnd
EndIf
EndFunc
; Recursive callback cleanup
Func __ArrayDisplay_CallBackFree($hWnd)
Local $aHandle_Proc = Eval('arraydisplayprocdata')
Local $sFuncName = "SetWindowLongW"
If @AutoItX64 Then $sFuncName = "SetWindowLongPtrW"
;ConsoleWrite('- DELETE ' & $hWnd & @TAB & Eval($hWnd) & @CR)
Local $aSplitData = StringSplit(Eval($hWnd), '|', 2)
Assign($hWnd, 0, 2)
ReDim $aSplitData[UBound($aSplitData) + 1]
$aSplitData[UBound($aSplitData) -1] = $hWnd
Local $iIndex, $hParent, $hChld
For $sVal In $aSplitData
$hChld = __ArrayDisplay_GethWnd($sVal)
If Eval($hChld) Then
__ArrayDisplay_CallBackFree($hChld)
$aHandle_Proc = Eval('arraydisplayprocdata')
ContinueLoop
EndIf
If Not $hChld Then ContinueLoop
$iIndex = _ArraySearch($aHandle_Proc, $hChld, 1, 0, 0, 0, 1, 0)
If $iIndex == -1 Then ContinueLoop
DllCall("user32.dll", "long_ptr", $sFuncName, "hwnd", $aHandle_Proc[$iIndex][0], "int", -4, "long_ptr", $aHandle_Proc[$iIndex][1])
DllCallbackFree($aHandle_Proc[$iIndex][2])
$hParent = $aHandle_Proc[$iIndex][4]
_ArrayDelete($aHandle_Proc, $iIndex)
$aHandle_Proc[0][0] -= 1
Next
Assign('arraydisplayprocdata', $aHandle_Proc, 2)
Return $hParent
EndFunc
; Checks whether this array cell has been opened for viewing
Func __ArrayDisplay_IsOpen($sid, $sSub)
Return (StringInStr($sid, $sSub) > 0)
EndFunc
; Retrieves from the hWnd string the window associated with the desired part of the string
Func __ArrayDisplay_GethWnd($sid, $sSub = '')
Local $aData = StringRegExp($sid, '[0-9A-Fa-f]{16}|[0-9A-Fa-f]{8}', 1, StringInStr($sid, $sSub))
If @error Then Return 0
Return HWnd('0x' & $aData[0])
EndFunc
; Removes the part with hWnd from the string
; Writes the string to a variable with the name of the parent window
Func __ArrayDisplay_DelhWnd($hWnd, $hParent)
Local $sid = Eval($hParent)
$sid = StringRegExpReplace($sid, '(Array......;' & $hWnd & '|Array...;' & $hWnd & ')', '')
$sid = StringReplace($sid, '||', '|')
If $sid == '|' Then $sid = ''
;ConsoleWrite('- DEL HWND ' & $hWnd &@TAB & $sid & @CR)
Assign($hParent, $sid, 2)
GUIDelete($hWnd)
WinActivate($hParent)
EndFunc
#EndRegion End modification region
Готовые файлы для замены оригинальных в папке AutoIt3\include:
- Автор
- musicstashall
Вложения
Последнее редактирование: