Что нового

Режим OnEvent и приоритетность

VadimKHL

Новичок
Сообщения
155
Репутация
0
Всем привет!
Нужна помощь новичку.
Ситуация такая. Есть обработка кнопок в режиме OnEvent.
При их нажатии происходит передача данных в Com порт и принятие ответного сообщения от устройства.
Так же, в бесконечном цикле While каждые 100 мс происходит обмен данных через ком порт.

В итоге, иногда при нажатии кнопок нарушается логика обмена данными,
т.е. в цикле посылаются данные в ком порт, потом происходит нажатие кнопки, которое нарушает режим работы запрос/ответ.

Каким способом можно решить данную проблему?

Всем спасибо!
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
Возможно во время обмена данными с СОМ портом отключать режим OnEvent , после окончания - включать. Таким образом во время обмена данными скрипт не будет реагировать на нажатие кнопки. Или , как вариант на нажатие кнопки привязать просто установку какого-нибудь флага нажатия кнопки и обработку флага по кнопке производить вне цикла работы с СОМ портом.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
ra4o сказал(а):
Возможно во время обмена данными с СОМ портом отключать режим OnEvent , после окончания - включать. Таким образом во время обмена данными скрипт не будет реагировать на нажатие кнопки. Или , как вариант на нажатие кнопки привязать просто установку какого-нибудь флага нажатия кнопки и обработку флага по кнопке производить вне цикла работы с СОМ портом.

Возможно. Но тогда смысл режима OnEvent вообще теряется.

А возможно ли в режиме OnEvent запустить таймер, который допустим каждые 100 мс генерирует событие, и выполняет функцию, блокируя выполнение других событий?
Т.е. как будто обычная кнопка в режиме OnEvent, которая нажимается каждые 100 мс автоматически, а не пользователем?
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
каждые 100 мс генерирует событие, и выполняет функцию
Код:
AdlibRegister("_MyFunc", 100)

Но это Вас не спасёт от не вовремя нажатых кнопок в режиме OnEvent.
Возможно. Но тогда смысл режима OnEvent вообще теряется.
Если объём информации не большой, а судя по тому. что Вы читаете/пишите в СОМ порт каждые 100 мс оно так и есть. то отключение режима OnEvent на время работы с СОМ портом Вы и не заметите. Ведь у Вас задача
блокируя выполнение других событий?
- не принимать никаких прерываний при обмене данными, тогда и решение :
во время обмена данными с СОМ портом отключать режим OnEvent
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
ra4o сказал(а):
тогда и решение :
во время обмена данными с СОМ портом отключать режим OnEvent

Я думаю это не верное решение. Ситуация такая,
отключаем OnEvent, происходит обмен данными по COM, а в это время пользователь кликает по кнопке.
Ведь после включения OnEvent кнопка не будет отработана?
В итоге безответный клик по кнопке?
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
Выставляйте флаги (разрешения) либо в цикле, либо в функциях-обработчиках. И проверяйте их, соответственно, либо в функциях, либо в цикле.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
InnI сказал(а):
VadimKHL
Выставляйте флаги (разрешения) либо в цикле, либо в функциях-обработчиках. И проверяйте их, соответственно, либо в функциях, либо в цикле.

Т.е. при нажатии кнопок, вызывать функции, которые просто поднимают флаги (биты) в переменной, а в цикле While, после обмена данными с COM,
обрабатывать нажатые кнопки?

А в чем тогда будет разница данного решения по сравнению с использованием режима MessegeLoop?
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
разница данного решения по сравнению с использованием режима MessegeLoop
Принципиальной разницы нет. Вопрос только в скорости реакции интерфейса. Как написано в справке по MessageLoop "вы должны убедиться, что вызываете функцию довольно часто (более 20-ти раз в секунду), иначе ваш GUI не будет откликаться на взаимодействие с элементами управления". А если вы в цикл обмена данными включите GUIGetMsg(), то всё равно придётся запоминать нажатые кнопки и обрабатывать их при выходе из цикла.
 

ra4o

AutoIT Гуру
Сообщения
1,165
Репутация
246
Ведь даже , если устанавливать флаг нажатия кнопки скрипту нужно будет выйти из цикла работы с СОМ портом, установить флаг и вернуться обратно. Если все-же необходимо не прерывать обработку данных с СОМ порта и работать одновременно с интерфейсом , тогда работу с СОМ портом можно вынести в отдельный скрипт (dll итп) и при необходимости из основного скрипта вызывать скрипт обработки данных.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
ra4o сказал(а):
Ведь даже , если устанавливать флаг нажатия кнопки скрипту нужно будет выйти из цикла работы с СОМ портом, установить флаг и вернуться обратно.

Похоже вопрос не верно описал.

Функцию работы с COM портом, которая выполняется каждые 100 мс прерывать можно сколько угодно, хоть на 10 секунд.
Нельзя нарушать условие ЗАПРОС (сообщение от ПК) - ОТВЕТ (ПК принимает).

Конкретно как происходит крах:
Функция, которая выполняется каждые 100 мс посылает запрос, и ожидает ответ.
В это время пользователь нажал кнопку, сразу посылается НОВЫЙ ЗАПРОС, а на предыдущий запрос ответ еще не пришел.
Функция нажатия кнопки в итоге получает ответ, но не на свой запрос, а от предыдущего запроса.

Вот где проблема.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
Все зависит от загруженности МК. Ответ может придти в интервале от 1 мс до 200 мс.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
Для MessageLoop многовато... но попробовать можно. Тут зависит от того, как часто кнопки нажимаются и как быстро нужна реакция на нажатие.
В противном случае придётся делать гибрид - либо с флагами, либо с вкл/выкл режима.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
Накидал тестовую прогу.
OnEvent очень интересно работает.
он все события нажатия кнопок ставит в очередь. И это дает 100 процентов выполнения всех операций с GUI.
Для меня это самый правильный вариант.

Но как сгенерить события OnEvent программно, а не нажатием кнопки, что бы каждые 100 мс добавлялась в очередь еще одна функция?

Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>

Opt("GUIOnEventMode", 1) ; Включить режим отслеживания событий GUI.

; ====================================================================================================================
; Создаем визуальное окно и объекты в нем.
; ====================================================================================================================

; Создать визуальное окно.
$WINGUI = GUICreate("TEST", 470, 245, -1, -1, BitOr($WS_POPUP, $WS_BORDER))

; Информауионные строки.
$lbTMR1 = GUICtrlCreateLabel("TMR1:", 10, 10, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR2 = GUICtrlCreateLabel("TMR2:", 10, 25, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR3 = GUICtrlCreateLabel("TMR3:", 10, 40, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

$idTMR1 = GUICtrlCreateLabel("0", 55, 10, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR2 = GUICtrlCreateLabel("0", 55, 25, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR3 = GUICtrlCreateLabel("0", 55, 40, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

; Кнопки.
GUICtrlCreateButton("TMR1", 260, 70, 100, 25)
GUICtrlSetOnEvent(-1, "_TMR1")
GUICtrlCreateButton("TMR2", 260, 95, 100, 25)
GUICtrlSetOnEvent(-1, "_TMR2")
GUICtrlCreateButton("TMR3", 260, 120, 100, 25)
GUICtrlSetOnEvent(-1, "_TMR3")

; Системные события.
GUISetOnEvent($GUI_EVENT_CLOSE, "_CLOSEEvent")

GUISetState(@SW_SHOW, $WINGUI)

While 1
   Sleep(100)
WEnd


Func _TMR1()
   For $TMR1 = 1 To 10
	  GUICtrlSetData ($idTMR1, $TMR1)
	  sleep (500)
   Next
EndFunc

Func _TMR2()
   For $TMR2 = 1 To 10
	  GUICtrlSetData ($idTMR2, $TMR2)
	  sleep (500)
   Next
EndFunc

Func _TMR3()
   For $TMR3 = 1 To 10
	  GUICtrlSetData ($idTMR3, $TMR3)
	  sleep (500)
   Next
EndFunc


; ====================================================================================================================
; Функции системных событий.
; ====================================================================================================================
Func _CLOSEEvent()
    Exit
EndFunc
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
сгенерить события OnEvent программно, а не нажатием кнопки
Нужно просто программно нажать кнопку ;)
Код:
AdlibRegister("BtnClick", 100)

Func BtnClick()
  GUICtrlSendMsg($idBtn, 0xF5, 0, 0) ; $BM_CLICK
;~   ControlClick($WINGUI, "", "TMR1") ; или так
EndFunc



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

VadimKHL [?]
OnEvent очень интересно работает.
он все события нажатия кнопок ставит в очередь
На самом деле очередь получается из-за того, что очередное событие не может прервать функцию, вызванную другим событием.

В режиме MessageLoop события тоже встают в очередь. Просто эта очередь "забивается" событиями движения курсора мыши. А функция GuiGetMsg() за один вызов читает одно событие. Вот и получается, что если её вызывать редко, то интерфейс "тормозит".

Вот вариант вашей "тестовой проги" в режиме MessageLoop (все события $GUI_EVENT_MOUSEMOVE вычищаются и интерфейс не тормозит)
Код:
#include <GUIConstants.au3>

$WINGUI = GUICreate("TEST", 470, 245, -1, -1, BitOr($WS_POPUP, $WS_BORDER))

$lbTMR1 = GUICtrlCreateLabel("TMR1:", 10, 10, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR2 = GUICtrlCreateLabel("TMR2:", 10, 25, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR3 = GUICtrlCreateLabel("TMR3:", 10, 40, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

$idTMR1 = GUICtrlCreateLabel("0", 55, 10, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR2 = GUICtrlCreateLabel("0", 55, 25, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR3 = GUICtrlCreateLabel("0", 55, 40, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

$Btn1 = GUICtrlCreateButton("TMR1", 260, 70, 100, 25)
$Btn2 = GUICtrlCreateButton("TMR2", 260, 95, 100, 25)
$Btn3 = GUICtrlCreateButton("TMR3", 260, 120, 100, 25)

GUISetState(@SW_SHOW, $WINGUI)

$timer = TimerInit()

While 1
  Do
    $msg = GUIGetMsg()
  Until $msg <> $GUI_EVENT_MOUSEMOVE
  Switch $msg
    Case $GUI_EVENT_CLOSE
       Exit
    Case $Btn1
       For $TMR1 = 1 To 10
          GUICtrlSetData ($idTMR1, $TMR1)
          sleep(300)
       Next
    Case $Btn2
       For $TMR2 = 1 To 10
          GUICtrlSetData ($idTMR2, $TMR2)
          sleep(300)
       Next
    Case $Btn3
       For $TMR3 = 1 To 10
          GUICtrlSetData ($idTMR3, $TMR3)
          sleep(300)
       Next
    Case 0
      If TimerDiff($timer) > 100 Then
        SendData()
        $timer = TimerInit()
      EndIf
  EndSwitch
WEnd

Func SendData()
  ConsoleWrite(sleep(300))
EndFunc
 

Naisho

Знающий
Сообщения
86
Репутация
12
Может так?

Код:
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
Opt("GUIOnEventMode", 1)

Global $bAuto = False, $bBusy = False, $bManual = False



#Region ### START Koda GUI section ### Form=
Local $Form1 = GUICreate("Form1", 401, 218, -1, -1)
GUISetOnEvent($GUI_EVENT_CLOSE, "Form1Close")
Local $Button1 = GUICtrlCreateButton("Start Auto Check", 64, 88, 128, 25)
GUICtrlSetOnEvent(-1, "Button1Click")
Local $Button2 = GUICtrlCreateButton("Manual Check", 224, 88, 128, 25)
GUICtrlSetOnEvent(-1, "Button2Click")
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###

While 1
	Sleep(100)
WEnd

Func Button1Click()

	$bAuto = ($bAuto)?(False):(True)

	If $bAuto Then
		GUICtrlSetData($Button1, "Stop Auto Check")
		AdlibRegister("CheckFunc",3000)
	Else
		GUICtrlSetData($Button1, "Start Auto Check")
		AdlibUnRegister("CheckFunc")
	EndIf

EndFunc

Func Button2Click()

	$bManual = True

	GUICtrlSetBkColor($Button2,0xffff00)

	If Not $bAuto Then AdlibRegister("CheckFunc",20)

EndFunc

Func Form1Close()
	Exit
EndFunc

Func CheckFunc()

	If $bBusy Then Return SetExtended(1)

	If $bManual Then
		If Not $bAuto Then AdlibUnRegister("CheckFunc")
		$bManual = False
		GUICtrlSetStyle($Button2, $GUI_SS_DEFAULT_BUTTON)
	EndIf

	If $bAuto Then GUICtrlSetBkColor($Button1,0xffff00)

	$bBusy = True
	Action()
	$bBusy = False

	If $bAuto Then GUICtrlSetStyle($Button1, $GUI_SS_DEFAULT_BUTTON)

EndFunc

Func Action()
	ConsoleWrite("!!!" & @CRLF)
	Sleep(Random(1000,2000))
EndFunc
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
Добрый день!

Проверил работу AdlibRegister.
Проблему не решает.
Функция, вызванная AdlibRegister, прерывается функцией, при нажатии кнопки.

Разбираюсь с вариантами, предложенными выше...
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
Функция, вызванная AdlibRegister, прерывается функцией, при нажатии кнопки
Такое поведение наблюдается при включении режима OnEvent. И ещё в этом режиме функция AdlibRegister не может прервать функцию-обработчик события. А в режиме MessageLoop всё наоборот.
 
Автор
V

VadimKHL

Новичок
Сообщения
155
Репутация
0
Пока вышел из положения, путем введения флагов (режим OnEvent):
Код:
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <StaticConstants.au3>

Opt("GUIOnEventMode", 1) ; Включить режим отслеживания событий GUI.

Global $FLAGBUT = 0

; ====================================================================================================================
; Создаем визуальное окно и объекты в нем.
; ====================================================================================================================

; Создать визуальное окно.
$WINGUI = GUICreate("TEST", 470, 245, -1, -1, BitOr($WS_POPUP, $WS_BORDER))

; Информауионные строки.
$lbTMR1 = GUICtrlCreateLabel("TMR1:", 10, 10, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR2 = GUICtrlCreateLabel("TMR2:", 10, 25, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR3 = GUICtrlCreateLabel("TMR3:", 10, 40, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$lbTMR4 = GUICtrlCreateLabel("TMR4:", 10, 55, 40, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

$idTMR1 = GUICtrlCreateLabel("0", 55, 10, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR2 = GUICtrlCreateLabel("0", 55, 25, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR3 = GUICtrlCreateLabel("0", 55, 40, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)
$idTMR4 = GUICtrlCreateLabel("0", 55, 55, 65, 15, $SS_LEFTNOWORDWRAP, $GUI_WS_EX_PARENTDRAG)

; Кнопки.
GUICtrlCreateButton("TMR1", 260, 70, 100, 25)
GUICtrlSetOnEvent(-1, "BCLK_TMR1")
GUICtrlCreateButton("TMR2", 260, 95, 100, 25)
GUICtrlSetOnEvent(-1, "BCLK_TMR2")
GUICtrlCreateButton("TMR3", 260, 120, 100, 25)
GUICtrlSetOnEvent(-1, "BCLK_TMR3")

; Системные события.
GUISetOnEvent($GUI_EVENT_CLOSE, "_CLOSEEvent")

GUISetState(@SW_SHOW, $WINGUI)

Global $TMRUPDATE = TimerInit()

While 1

   If BitAND($FLAGBUT, 1) > 0 Then
	  $FLAGBUT = $FLAGBUT - 1
	  _TMR1()
   EndIf
   If BitAND($FLAGBUT, 2) > 0 Then
	  $FLAGBUT = $FLAGBUT - 2
	  _TMR2()
   EndIf
   If BitAND($FLAGBUT, 4) > 0 Then
	  $FLAGBUT = $FLAGBUT - 4
	  _TMR3()
   EndIf

   If TimerDiff($TMRUPDATE) > 100 Then
	  $TMRUPDATE = TimerInit()
	  _TMR4()
   EndIf

WEnd

Func BCLK_TMR1()
   $FLAGBUT = BitOR(1, $FLAGBUT) ; Установить 0 бит.
EndFunc
Func BCLK_TMR2()
   $FLAGBUT = BitOR(2, $FLAGBUT) ; Установить 1 бит.
EndFunc
Func BCLK_TMR3()
   $FLAGBUT = BitOR(4, $FLAGBUT) ; Установить 2 бит.
EndFunc

Func _TMR1()
   For $TMR1 = 1 To 5
	  GUICtrlSetData ($idTMR1, $TMR1)
	  sleep (500)
   Next
EndFunc

Func _TMR2()
   For $TMR2 = 1 To 5
	  GUICtrlSetData ($idTMR2, $TMR2)
	  sleep (500)
   Next
EndFunc

Func _TMR3()
   For $TMR3 = 1 To 5
	  GUICtrlSetData ($idTMR3, $TMR3)
	  sleep (500)
   Next
EndFunc

Func _TMR4()
   For $TMR4 = 1 To 5
	  GUICtrlSetData ($idTMR4, $TMR4)
	  sleep (500)
   Next
EndFunc

; ====================================================================================================================
; Функции системных событий.
; ====================================================================================================================
Func _CLOSEEvent()
    Exit
EndFunc


Но очередность в данном случае не соблюдается.

Думаю, как можно решить другим способом.
Может спасут GUICtrlSendMsg или ControlClick, разбираюсь с ними.
 

InnI

AutoIT Гуру
Сообщения
4,912
Репутация
1,429
VadimKHL
очередность в данном случае не соблюдается
Естественно. Если вы сначала нажимаете "большую" кнопку (например, +4), затем меньшую (+2), после чего проверяете СНАЧАЛА на наличие 2... конечно, 2 там будет. Как бы вы кнопки не нажимали, очередь у вас всегда будет от "меньшей" к "большей". Что-то вы перемудрили.

Чем вам не нравится код из вашего сообщения #13 с добавлением AdlibRegister и GUICtrlSendMsg из моего сообщения #14 ?
 
Верх