Что нового

[Окна, Диалоги] __ArrayDisplay при обработке сообщений WM_NOTIFY

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Известно,что при попытке использовать ф-ию
_ArrayDisplay в ф-ии WM_NOTIFY
возникает зависание скрипта.

Все проблемы из-за наличия в ф-ии цикла обработки сообщений от своего окна
Небольшие изменения в ф-ии _ArrayDisplay
позволяют устранить эту проблему:

Пример и измененная ф-я :
Код:
#include <WindowsConstants.au3>
#include <GuiConstantsEx.au3>
#include <GuiListView.au3>
;#include <Array.au3>

$Gui = GUICreate("Test", 200, 250)

$hListView = _GUICtrlListView_Create($GUI, "Items|SubItems", 5, 2, 190, 200, BitOR($LVS_EDITLABELS, $LVS_REPORT))
Dim $aData[4][2]=[["Борис", 44], ["Анна", 55], ["Света", 11], ["Миша",22]]

For $i=0 To 3
	$iItem = _GUICtrlListView_AddItem($hListView, "")
	For $j=0 To 1
		 _GUICtrlListView_SetItemText($hListView, $iItem, $aData[$i][$j], $j)
	Next
Next

$Label=GUICtrlCreateLabel('',5, 220, 100, 25,0x1000)

GUIRegisterMsg($WM_NOTIFY, "WM_NOTIFY")
GUISetState()

While 1
    $msg = GUIGetMsg()
    Switch $msg
    Case $GUI_EVENT_CLOSE
	   Exit
    
    EndSwitch
WEnd
    
;==============================================
Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
;================================================================== 
    #forceref $hWnd, $iMsg, $iwParam
    Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView
    
    $hWndListView = $hListView
    If Not IsHWnd($hListView) Then $hWndListView = GUICtrlGetHandle($hListView)

    $tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
    $hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
    $iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
    $iCode = DllStructGetData($tNMHDR, "Code")
    Switch $hWndFrom
        Case $hWndListView;, $hWndListView2
            Switch $iCode
                Case $NM_CLICK
                    Global $aHit = _GUICtrlListView_SubItemHitTest($hWndFrom)
                    GUICtrlSetData($Label,_GUICtrlListView_GetItemText($hWndFrom, $aHit [0],$aHit [1]))
					__Array_Display($aHit)
            EndSwitch
    EndSwitch 
    Return $GUI_RUNDEFMSG
EndFunc ; ===> WM_NOTIFY

; #FUNCTION# ====================================================================================================================
; Name...........: __ArrayDisplay
; Description ...: Displays given 1D or 2D array array in a listview.
; Syntax.........: __ArrayDisplay(Const ByRef $avArray[, $sTitle = "Array: ListView Display"[, $iItemLimit = -1[, $iTranspose = 0[, $sSeparator = ""[, $sReplace = "|"[, $sHeader = ""]]]]]])
; Parameters ....: $avArray    - Array to display
;                  $sTitle     - [optional] Title to use for window
;                  $iItemLimit - [optional] Maximum number of listview items (rows) to show
;                  $iTranspose - [optional] If set differently than default, will transpose the array if 2D
;                  $sSeparator - [optional] Change Opt("GUIDataSeparatorChar") on-the-fly
;                  $sReplace   - [optional] String to replace any occurrence of $sSeparator with in each array element
;                  $sheader     - [optional] Header column names
; Return values .: Success - 1
;                  Failure - 0, sets @error:
;                  |1 - $avArray is not an array
;                  |2 - $avArray has too many dimensions (only up to 2D supported)
; Author ........: randallc, Ultima
; Modified.......: Gary Frost (gafrost), Ultima, Zedna, jpm
; Remarks .......:
; Related .......:
; Link ..........:
; Example .......: Yes
; ===============================================================================================================================
Func __Array_Display(Const ByRef $avArray, $sTitle = "Array: ListView Display", $iItemLimit = -1, $iTranspose = 0, $sSeparator = "", $sReplace = "|", $sHeader = "")
	If Not IsArray($avArray) Then Return SetError(1, 0, 0)
	; Dimension checking
	Local $iDimension = UBound($avArray, 0), $iUBound = UBound($avArray, 1) - 1, $iSubMax = UBound($avArray, 2) - 1
	If $iDimension > 2 Then Return SetError(2, 0, 0)

	; Separator handling
;~     If $sSeparator = "" Then $sSeparator = Chr(1)
	If $sSeparator = "" Then $sSeparator = Chr(124)

	;  Check the separator to make sure it's not used literally in the array
	If _ArraySearch($avArray, $sSeparator, 0, 0, 0, 1) <> -1 Then
		For $x = 1 To 255
			If $x >= 32 And $x <= 127 Then ContinueLoop
			Local $sFind = _ArraySearch($avArray, Chr($x), 0, 0, 0, 1)
			If $sFind = -1 Then
				$sSeparator = Chr($x)
				ExitLoop
			EndIf
		Next
	EndIf

	; Declare variables
	Local $vTmp, $iBuffer = 64
	Local $iColLimit = 250
	;Local $iOnEventMode = Opt("GUIOnEventMode", 0), $sDataSeparatorChar = Opt("GUIDataSeparatorChar", $sSeparator)
	Local  $sDataSeparatorChar = Opt("GUIDataSeparatorChar", $sSeparator); *** Изменено
	Global $iOnEventMode = Opt("GUIOnEventMode", 0)                             ; *** Изменено
	; Swap dimensions if transposing
	If $iSubMax < 0 Then $iSubMax = 0
	If $iTranspose Then
		$vTmp = $iUBound
		$iUBound = $iSubMax
		$iSubMax = $vTmp
	EndIf

	; Set limits for dimensions
	If $iSubMax > $iColLimit Then $iSubMax = $iColLimit
	If $iItemLimit < 1 Then $iItemLimit = $iUBound
	If $iUBound > $iItemLimit Then $iUBound = $iItemLimit

	; Set header up
	If $sHeader = "" Then
		$sHeader = "Row  "	; blanks added to adjust column size for big number of rows
		For $i = 0 To $iSubMax
			$sHeader &= $sSeparator & "Col " & $i
		Next
	EndIf

	; Convert array into text for listview
	Local $avArrayText[$iUBound + 1]
	For $i = 0 To $iUBound
		$avArrayText[$i] = "[" & $i & "]"
		For $j = 0 To $iSubMax
			; Get current item
			If $iDimension = 1 Then
				If $iTranspose Then
					$vTmp = $avArray[$j]
				Else
					$vTmp = $avArray[$i]
				EndIf
			Else
				If $iTranspose Then
					$vTmp = $avArray[$j][$i]
				Else
					$vTmp = $avArray[$i][$j]
				EndIf
			EndIf

			; Add to text array
			$vTmp = StringReplace($vTmp, $sSeparator, $sReplace, 0, 1)
			$avArrayText[$i] &= $sSeparator & $vTmp

			; Set max buffer size
			$vTmp = StringLen($vTmp)
			If $vTmp > $iBuffer Then $iBuffer = $vTmp
		Next
	Next
	$iBuffer += 1

	; GUI Constants
	Local Const $_ARRAYCONSTANT_GUI_DOCKBORDERS = 0x66
	Local Const $_ARRAYCONSTANT_GUI_DOCKBOTTOM = 0x40
	Local Const $_ARRAYCONSTANT_GUI_DOCKHEIGHT = 0x0200
	Local Const $_ARRAYCONSTANT_GUI_DOCKLEFT = 0x2
	Local Const $_ARRAYCONSTANT_GUI_DOCKRIGHT = 0x4
	Local Const $_ARRAYCONSTANT_GUI_EVENT_CLOSE = -3
	Local Const $_ARRAYCONSTANT_LVIF_PARAM = 0x4
	Local Const $_ARRAYCONSTANT_LVIF_TEXT = 0x1
	Local Const $_ARRAYCONSTANT_LVM_GETCOLUMNWIDTH = (0x1000 + 29)
	Local Const $_ARRAYCONSTANT_LVM_GETITEMCOUNT = (0x1000 + 4)
	Local Const $_ARRAYCONSTANT_LVM_GETITEMSTATE = (0x1000 + 44)
	Local Const $_ARRAYCONSTANT_LVM_INSERTITEMW = (0x1000 + 77)
	Local Const $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE = (0x1000 + 54)
	Local Const $_ARRAYCONSTANT_LVM_SETITEMW = (0x1000 + 76)
	Local Const $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT = 0x20
	Local Const $_ARRAYCONSTANT_LVS_EX_GRIDLINES = 0x1
	Local Const $_ARRAYCONSTANT_LVS_SHOWSELALWAYS = 0x8
	Local Const $_ARRAYCONSTANT_WS_EX_CLIENTEDGE = 0x0200
	Local Const $_ARRAYCONSTANT_WS_MAXIMIZEBOX = 0x00010000
	Local Const $_ARRAYCONSTANT_WS_MINIMIZEBOX = 0x00020000
	Local Const $_ARRAYCONSTANT_WS_SIZEBOX = 0x00040000
	Local Const $_ARRAYCONSTANT_tagLVITEM = "int Mask;int Item;int SubItem;int State;int StateMask;ptr Text;int TextMax;int Image;int Param;int Indent;int GroupID;int Columns;ptr pColumns"

	Local $iAddMask = BitOR($_ARRAYCONSTANT_LVIF_TEXT, $_ARRAYCONSTANT_LVIF_PARAM)
	Local $tBuffer = DllStructCreate("wchar Text[" & $iBuffer & "]"), $pBuffer = DllStructGetPtr($tBuffer)
	Local $tItem = DllStructCreate($_ARRAYCONSTANT_tagLVITEM), $pItem = DllStructGetPtr($tItem)
	DllStructSetData($tItem, "Param", 0)
	DllStructSetData($tItem, "Text", $pBuffer)
	DllStructSetData($tItem, "TextMax", $iBuffer)

	; Set interface up
	Local $iWidth = 640, $iHeight = 480
	;Local $hGUI = GUICreate($sTitle, $iWidth, $iHeight, Default, Default, BitOR($_ARRAYCONSTANT_WS_SIZEBOX, $_ARRAYCONSTANT_WS_MINIMIZEBOX, $_ARRAYCONSTANT_WS_MAXIMIZEBOX))
	Global $hArrayDisplayGUI = GUICreate($sTitle, $iWidth, $iHeight, Default, Default, BitOR($_ARRAYCONSTANT_WS_SIZEBOX, $_ARRAYCONSTANT_WS_MINIMIZEBOX, $_ARRAYCONSTANT_WS_MAXIMIZEBOX)); *** Изменено
	Local $aiGUISize = WinGetClientSize($hArrayDisplayGUI)
	Local $hListView = GUICtrlCreateListView($sHeader, 0, 0, $aiGUISize[0], $aiGUISize[1] - 26, $_ARRAYCONSTANT_LVS_SHOWSELALWAYS)
	;Local $hCopy = GUICtrlCreateButton("Copy Selected", 3, $aiGUISize[1] - 23, $aiGUISize[0] - 6, 20)
	GUICtrlSetResizing($hListView, $_ARRAYCONSTANT_GUI_DOCKBORDERS)
	;GUICtrlSetResizing($hCopy, $_ARRAYCONSTANT_GUI_DOCKLEFT + $_ARRAYCONSTANT_GUI_DOCKRIGHT + $_ARRAYCONSTANT_GUI_DOCKBOTTOM + $_ARRAYCONSTANT_GUI_DOCKHEIGHT)
	GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_LVS_EX_GRIDLINES, $_ARRAYCONSTANT_LVS_EX_GRIDLINES)
	GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT, $_ARRAYCONSTANT_LVS_EX_FULLROWSELECT)
	GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_SETEXTENDEDLISTVIEWSTYLE, $_ARRAYCONSTANT_WS_EX_CLIENTEDGE, $_ARRAYCONSTANT_WS_EX_CLIENTEDGE)

	; Fill listview
	Local $aItem
	For $i = 0 To $iUBound
		If GUICtrlCreateListViewItem($avArrayText[$i], $hListView) = 0 Then
			; use GUICtrlSendMsg() to overcome AutoIt limitation
			$aItem = StringSplit($avArrayText[$i], $sSeparator)
			DllStructSetData($tBuffer, "Text", $aItem[1])

			; Add listview item
			DllStructSetData($tItem, "Item", $i)
			DllStructSetData($tItem, "SubItem", 0)
			DllStructSetData($tItem, "Mask", $iAddMask)
			GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_INSERTITEMW, 0, $pItem)

			; Set listview subitem text
			DllStructSetData($tItem, "Mask", $_ARRAYCONSTANT_LVIF_TEXT)
			For $j = 2 To $aItem[0]
				DllStructSetData($tBuffer, "Text", $aItem[$j])
				DllStructSetData($tItem, "SubItem", $j - 1)
				GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_SETITEMW, 0, $pItem)
			Next
		EndIf
	Next

	; adjust window width
	$iWidth = 0
	For $i = 0 To $iSubMax + 1
		$iWidth += GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_GETCOLUMNWIDTH, $i, 0)
	Next
	If $iWidth < 250 Then $iWidth = 230
	$iWidth += 20

	If $iWidth > @DesktopWidth Then $iWidth = @DesktopWidth - 100

	WinMove($hArrayDisplayGUI, "", (@DesktopWidth - $iWidth)/2, Default, $iWidth)

	; Show dialog
	GUISetState(@SW_SHOW, $hArrayDisplayGUI)
#cs
	While 1
		Switch GUIGetMsg()
			Case $_ARRAYCONSTANT_GUI_EVENT_CLOSE
				ExitLoop

			Case $hCopy
				Local $sClip = ""

				; Get selected indices [ _GUICtrlListView_GetSelectedIndices($hListView, True) ]
				Local $aiCurItems[1] = [0]
				For $i = 0 To GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_GETITEMCOUNT, 0, 0)
					If GUICtrlSendMsg($hListView, $_ARRAYCONSTANT_LVM_GETITEMSTATE, $i, 0x2) Then
						$aiCurItems[0] += 1
						ReDim $aiCurItems[$aiCurItems[0] + 1]
						$aiCurItems[$aiCurItems[0]] = $i
					EndIf
				Next

				; Generate clipboard text
				If Not $aiCurItems[0] Then
					For $sItem In $avArrayText
						$sClip &= $sItem & @CRLF
					Next
				Else
					For $i = 1 To UBound($aiCurItems) - 1
						$sClip &= $avArrayText[$aiCurItems[$i]] & @CRLF
					Next
				EndIf
				ClipPut($sClip)
		EndSwitch
	WEnd
	GUIDelete($hArrayDisplayGUI)
#ce
	;Opt("GUIOnEventMode", $iOnEventMode)
	Opt("GUIOnEventMode", 1); *** Изменено
	Opt("GUIDataSeparatorChar", $sDataSeparatorChar)

	GUISetOnEvent($_ARRAYCONSTANT_GUI_EVENT_CLOSE, "_CLOSEClicked"); *** Добавлено и ИЗМЕНЕНО

	Return 1
EndFunc   ;==>__ArrayDisplay

Func _CLOSEClicked()
	GUIDelete($hArrayDisplayGUI)
	Opt ("GUIOnEventMode",$iOnEventMode)
EndFunc
 

madmasles

Модератор
Глобальный модератор
Сообщения
7,790
Репутация
2,323
gregaz,
Пока не вынес из функции в начало
Код:
Global $hArrayDisplayGUI, $iOnEventMode
;и не заменил
;...
GUISetOnEvent($_ARRAYCONSTANT_GUI_EVENT_CLOSE, "CLOSEClicked")
;...
;на
;...
GUISetOnEvent($_ARRAYCONSTANT_GUI_EVENT_CLOSE, "_CLOSEClicked")
;...
У меня вылезали ошибки.
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
madmasles [?]
У меня вылезали ошибки.

У меня не было ошибки, т.к. я эту ф-ию занес в библиотеку Array.au3
а видимо библиотека <GuiListView.au3> ,обращаясь к Array.au3 выбирала установленный
там : CLOSEClicked

Так,что достаточно только изменить CLOSEClicked на: _CLOSEClicked.
А выносить переменные не надо .
Исправил в посте





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

Я старался делать как можно меньше изменений.
Все изменения это :

Замена внутреннего цикла цикла обработки сообщений(из-иа которойбыли все проблемы)
на ф-ию :_CLOSEClicked
И соотвественно кратковременного изменения режима обработки на OnEvent.
Для этого пришлось пару переменных объявить глобальными

Все это нужно только для закрытия дочернего окна без закрытия основного.
Другим способом не смог сделать.
Может кто сделает проще.

Есть еще один простой вариант :
Заменить только внутренний цикл на Sleep($iTime)
Тогда больше никаких изменений не надо . Окно само закроется через определенное время.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
А зачем вообще вызывать прерывающую функцию из обработчика? Это противоречит логике. А вообще, есть один трюк...

Код:
...

GUIRegisterMsg($WM_ACTIVATE, "WM_ACTIVATE")

...

Func WM_ACTIVATE($hWnd, $iMsg, $wParam, $lParam)
    Return $GUI_RUNDEFMSG
EndFunc ; ===> WM_ACTIVATE


Если вы добавите эти строки в ваш код, то можно будет вызвать стандартную функцию _ArrayDisplay() без каких либо танцев с бубном.

:smile:
 
Автор
G

gregaz

AutoIT Гуру
Сообщения
1,166
Репутация
299
Yashied [?]
А зачем вообще вызывать прерывающую функцию из обработчика? Это противоречит логике

Иногда сталкивался с подобной необходимостью.

А вообще, есть один трюк...

Классно.
А пояснить попроще можно что в этом случае происходит ?
 

Yashied

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