Что нового

[Окна, Диалоги] Зависание дочернего окна при вызове через GUIRegisterMsg

XpycT

Скриптер
Сообщения
380
Репутация
132
Всем Привет

Есть скрипт
Код:
#Region Includes

#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <ListViewConstants.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>
#EndRegion Includes
; #NoTrayIcon
Opt("TrayIconDebug", 1)
Opt("GUICloseOnESC", 1)

Dim $aData[11][4] = [[10, "", "", ""]]
For $i = 1 To $aData[0][0]
    $aData[$i][0] = "Flight Crew " & StringFormat("%02d", $i)
    $aData[$i][1] = StringFormat("%04d/%02d/%02d", Random(2009, 2010, 1), Random(1, 12, 1), Random(1, 28, 1))
    $aData[$i][2] = _DateAdd("Y", 1, $aData[$i][1])
Next

$hMainGui = GUICreate("Demo", 500, 300, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Close")

$hListView = GUICtrlCreateListView("Name|Pass Date|Expire Date", 5, 5, 490, 290)
GUICtrlSendMsg($hListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)

For $fc = 1 To $aData[0][0]
	_GUICtrlListView_AddItem($hListView, $aData[$fc][0], $fc - 1)
	_GUICtrlListView_AddSubItem($hListView, $fc - 1, $aData[$fc][1], 1)
	_GUICtrlListView_AddSubItem($hListView, $fc - 1, $aData[$fc][2], 2)
Next
GUICtrlSendMsg($hListView, 0x101E, 0, -1) ; Resize to widest value

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

_ShowEditor()

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			_Close()
	EndSwitch
WEnd

Func _ShowEditor()
	Local $iEditorLeft = -1, $iEditorTop = -1, $iEditorWidth = 510, $iEditorHeight = 400
	Local $EditorStyle = BitOR($WS_CAPTION, $WS_POPUP, $WS_DLGFRAME), $EditorExStyle =  BitOR($WS_EX_OVERLAPPEDWINDOW, $WS_EX_TOOLWINDOW)
	$hEditor = GUICreate("Demo Editor", $iEditorWidth, $iEditorHeight, $iEditorLeft, $iEditorTop, $EditorStyle, $EditorExStyle, $hMainGui)

	Local $iButtonLeft = 5, $iButtonTop = 50, $iButtonWidth = ($iEditorWidth) / 2, $iButtonHeight = 25
	$Confirm = GUICtrlCreateButton("Confirm", $iButtonLeft, $iButtonTop, $iButtonWidth, $iButtonHeight)
	$Cancel  = GUICtrlCreateButton("Cancel", $iButtonLeft + $iButtonWidth, $iButtonTop, $iButtonWidth, $iButtonHeight)

	GUISetState(@SW_DISABLE, $hMainGui)
	GUISetState(@SW_SHOW, $hEditor)
	GUISwitch($hEditor)

	While 1
		Switch GUIGetMsg()
			Case $Cancel
				ExitLoop
		EndSwitch
	WEnd

	GUISetState(@SW_ENABLE, $hMainGui)
	GUIDelete($hEditor)
	GUISwitch($hMainGui)
EndFunc

Func _Close()
	Exit
EndFunc   ;==>_Close

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg, $iwParam
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo

	If Not IsHWnd($hListView) Then $hListView = GUICtrlGetHandle($hListView)

	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")

	Switch $hWndFrom
		Case $hListView
			Switch $iCode
				Case $NM_DBLCLK
					$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
					$iItem = DllStructGetData($tInfo, "Index")
					$iSubItem = DllStructGetData($tInfo, "SubItem")

					If $iSubItem = 1 Then MsgBox(0, "", "$iItem = " & $iItem & " | $iSubItem = " & $iSubItem & @CR)
					If $iSubItem = 2 Then _ShowEditor()
			EndSwitch
	EndSwitch

	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY


При двойном клике на 3 колонке должно появиться дочернее окно. Если вызвать функцию отображения дочернего окна не по двойному клику то все работает нормально, а вот при вызове через двойной клик дочернее окно зависает.

Подскажите пожалуйста в чем проблема.
 

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
[quote author=AutoIt Help]Warning: blocking of running user functions which executes window messages with commands such as "Msgbox()" can lead to unexpected behavior, the return to the system should be as fast as possible !!!
[/quote]

Иными словами, нельзя "тормозить" выполнение функций прерывания. Используй Dummy.

Код:
#Include <WinAPI.au3>

...

$Dummy1 = GUICtrlCreateDummy()
$Dummy2 = GUICtrlCreateDummy()

...

While 1
    Switch GUIGetMsg()
		Case 0
			ContinueLoop
        Case $GUI_EVENT_CLOSE
            _Close()
		Case $Dummy1
			$Data = GUICtrlRead($Dummy1)
			MsgBox(0, "", "$iItem = " & _WinAPI_LoWord($Data) & " | $iSubItem = " & _WinAPI_HiWord($Data) & @CR)
		Case $Dummy2
			_ShowEditor()
    EndSwitch
WEnd

...

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	
...
		
	If $iSubItem = 1 Then GUICtrlSendToDummy($Dummy1, _WinAPI_MakeLong($iItem, $iSubItem))
	If $iSubItem = 2 Then GUICtrlSendToDummy($Dummy2)
					
...

EndFunc   ;==>WM_NOTIFY
 
Автор
X

XpycT

Скриптер
Сообщения
380
Репутация
132
Yashied [?]
Немного не понял как его (Dummy) использовать.

Немного поигравшись, определил что зависание вызывает GUIGetMsg. Если его убрать то окно показывается нормально. Есть подозрение что GUISwitch не переключает на дочернее окно.
 

Yashied

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

GUISwitch() здесь вообще не нужна. При удалении окна, AutoIt автоматически переключается на предыдущее окно, но и это не понадобится. GUIGetMsg() вообще не может вызывать зависания, никак. Зависания происходят потому, что в твоей функции WM_NOTIFY() стоит MsgBox() и _ShowEditor(), что КАТЕГОРИЧЕСКИ делать нельзя!!!

Dummy - это такой же элемент AutoIt, что и кнопка, список и т.д., но не имеющий GUI. Для чего он нужен? Именно для таких вот ситуаций. Dummy можно послать сообщение (+ какие-нибудь данные), которое, как раз, и отловит функция GUIGetMsg(). Таким образом, избегается принудительное подвисание функции обработки сообщения. Т.е. GUICtrlSendToDummy() не запускает сразу же MsgBox(), а просто посылает (ставит в очередь) сообщение, которое, в свою очередь, отловит GUIGetMsg(). И отловит она его только тогда, когда завершится выполнение WM_NOTIFY(), да и других функций обработки тоже.

К примеру, можно в функцию WM_NOTIFY() просто поставить Sleep(1000), и в результате скрипт тоже зависнет.

GUISwitch() нужна только на стадии создания GUI. Для GUIGetMsg() по барабану какой GUI в данный момент активен, она работает с ID элементов, которые, в свою очередь, всегда уникальны, независимо от того, сколько было создано окон.
 
Автор
X

XpycT

Скриптер
Сообщения
380
Репутация
132
Yashied
Спасибо за пояснение, теперь понятно. Приеду домой поиграюсь с Dummy.





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

Заработало

Вот рабочий скрипт, может кому пригодиться
Код:
#Region Includes

#include <Date.au3>
#include <GUIConstantsEx.au3>
#include <GuiListView.au3>
#include <ListViewConstants.au3>
#include <StructureConstants.au3>
#include <WindowsConstants.au3>
#EndRegion Includes
; #NoTrayIcon
Opt("TrayIconDebug", 1)
Opt("GUICloseOnESC", 1)

Dim $aData[11][4] = [[10, "", "", ""]]
For $i = 1 To $aData[0][0]
    $aData[$i][0] = "Flight Crew " & StringFormat("%02d", $i)
    $aData[$i][1] = StringFormat("%04d/%02d/%02d", Random(2009, 2010, 1), Random(1, 12, 1), Random(1, 28, 1))
    $aData[$i][2] = _DateAdd("Y", 1, $aData[$i][1])
Next

$hMainGui = GUICreate("Demo", 500, 300, -1, -1)
$hEditorDummy = GUICtrlCreateDummy()

$hListView = GUICtrlCreateListView("Name|Pass Date|Expire Date", 5, 5, 490, 290)
GUICtrlSendMsg($hListView, $LVM_SETEXTENDEDLISTVIEWSTYLE, $LVS_EX_GRIDLINES, $LVS_EX_GRIDLINES)

For $fc = 1 To $aData[0][0]
	_GUICtrlListView_AddItem($hListView, $aData[$fc][0], $fc - 1)
	_GUICtrlListView_AddSubItem($hListView, $fc - 1, $aData[$fc][1], 1)
	_GUICtrlListView_AddSubItem($hListView, $fc - 1, $aData[$fc][2], 2)
Next
GUICtrlSendMsg($hListView, 0x101E, 0, -1) ; Resize to widest value

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


While 1
	Switch GUIGetMsg()
		Case $hEditorDummy
			_ShowEditor()
		Case $GUI_EVENT_CLOSE
			_Close()
	EndSwitch
WEnd

Func _ShowEditor()
	GUISetState(@SW_DISABLE, $hMainGui)

	Local $iEditorLeft = -1, $iEditorTop = -1, $iEditorWidth = 510, $iEditorHeight = 400
	Local $EditorStyle = BitOR($WS_CAPTION, $WS_POPUP, $WS_DLGFRAME), $EditorExStyle =  BitOR($WS_EX_OVERLAPPEDWINDOW, $WS_EX_TOOLWINDOW)
	$hEditor = GUICreate("Demo Editor", $iEditorWidth, $iEditorHeight, $iEditorLeft, $iEditorTop, $EditorStyle, $EditorExStyle, $hMainGui)


	Local $iButtonLeft = 5, $iButtonTop = 50, $iButtonWidth = ($iEditorWidth) / 2, $iButtonHeight = 25
	$Confirm = GUICtrlCreateButton("Confirm", $iButtonLeft, $iButtonTop, $iButtonWidth, $iButtonHeight)
	$Cancel  = GUICtrlCreateButton("Cancel", $iButtonLeft + $iButtonWidth, $iButtonTop, $iButtonWidth, $iButtonHeight)

	GUISetState(@SW_SHOW, $hEditor)
	GUISwitch($hEditor)

	While 1
		Switch GUIGetMsg()
			Case $Cancel
				ExitLoop
		EndSwitch
	WEnd

	GUISetState(@SW_ENABLE, $hMainGui)
	GUIDelete($hEditor)
	GUISwitch($hMainGui)
EndFunc

Func _Close()
	Exit
EndFunc   ;==>_Close

Func WM_NOTIFY($hWnd, $iMsg, $iwParam, $ilParam)
	#forceref $hWnd, $iMsg, $iwParam
	Local $hWndFrom, $iIDFrom, $iCode, $tNMHDR, $hWndListView, $tInfo

	If Not IsHWnd($hListView) Then $hListView = GUICtrlGetHandle($hListView)

	$tNMHDR = DllStructCreate($tagNMHDR, $ilParam)
	$hWndFrom = HWnd(DllStructGetData($tNMHDR, "hWndFrom"))
	$iIDFrom = DllStructGetData($tNMHDR, "IDFrom")
	$iCode = DllStructGetData($tNMHDR, "Code")

	Switch $hWndFrom
		Case $hListView
			Switch $iCode
				Case $NM_DBLCLK
					$tInfo = DllStructCreate($tagNMITEMACTIVATE, $ilParam)
					$iItem = DllStructGetData($tInfo, "Index")
					$iSubItem = DllStructGetData($tInfo, "SubItem")

					If $iSubItem = 2 Then GUICtrlSendToDummy($hEditorDummy)
			EndSwitch
	EndSwitch

	Return $GUI_RUNDEFMSG
EndFunc   ;==>WM_NOTIFY
 
Верх