Русское сообщество AutoIt

Общий раздел по AutoIt => GUI - Графический интерфейс пользователя => Тема начата: VadimKHL от Декабрь 24, 2016, 17:41:09

Название: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Декабрь 24, 2016, 17:41:09
Всем привет!
Нужна помощь новичку.
Ситуация такая. Есть обработка кнопок в режиме OnEvent.
При их нажатии происходит передача данных в Com порт и принятие ответного сообщения от устройства.
Так же, в бесконечном цикле While каждые 100 мс происходит обмен данных через ком порт.

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

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

Всем спасибо!
Название: Re: Режим OnEvent и приоритетность
Отправлено: ra4o от Декабрь 27, 2016, 00:48:08
Возможно во время обмена данными с СОМ портом отключать режим OnEvent , после окончания - включать. Таким образом во время обмена данными скрипт не будет реагировать на нажатие кнопки.  Или , как вариант на нажатие кнопки привязать просто установку какого-нибудь флага нажатия кнопки и обработку флага по кнопке производить вне цикла работы с СОМ портом.
Название: Re: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Январь 11, 2017, 09:56:54
Возможно во время обмена данными с СОМ портом отключать режим OnEvent , после окончания - включать. Таким образом во время обмена данными скрипт не будет реагировать на нажатие кнопки.  Или , как вариант на нажатие кнопки привязать просто установку какого-нибудь флага нажатия кнопки и обработку флага по кнопке производить вне цикла работы с СОМ портом.

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

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


Название: Re: Режим OnEvent и приоритетность
Отправлено: ra4o от Январь 11, 2017, 11:58:19
Цитировать
каждые 100 мс генерирует событие, и выполняет функцию
Код: AutoIt [Выделить]
AdlibRegister("_MyFunc", 100)

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

Я думаю это не верное решение. Ситуация такая,
отключаем OnEvent, происходит обмен данными по COM, а в это время пользователь кликает по кнопке.
Ведь после включения OnEvent кнопка не будет отработана?
В итоге безответный клик по кнопке?
Название: Re: Режим OnEvent и приоритетность
Отправлено: InnI от Январь 12, 2017, 16:21:34
VadimKHL
Выставляйте флаги (разрешения) либо в цикле, либо в функциях-обработчиках. И проверяйте их, соответственно, либо в функциях, либо в цикле.
Название: Re: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Январь 13, 2017, 10:43:16
VadimKHL
Выставляйте флаги (разрешения) либо в цикле, либо в функциях-обработчиках. И проверяйте их, соответственно, либо в функциях, либо в цикле.

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

А в чем тогда будет разница данного решения по сравнению с использованием режима MessegeLoop?
Название: Re: Режим OnEvent и приоритетность
Отправлено: InnI от Январь 13, 2017, 13:01:06
VadimKHL
Цитировать
разница данного решения по сравнению с использованием режима MessegeLoop
Принципиальной разницы нет. Вопрос только в скорости реакции интерфейса. Как написано в справке по MessageLoop "вы должны убедиться, что вызываете функцию довольно часто (более 20-ти раз в секунду), иначе ваш GUI не будет откликаться на взаимодействие с элементами управления". А если вы в цикл обмена данными включите GUIGetMsg(), то всё равно придётся запоминать нажатые кнопки и обрабатывать их при выходе из цикла.
Название: Re: Режим OnEvent и приоритетность
Отправлено: ra4o от Январь 13, 2017, 14:39:33
Ведь даже , если устанавливать флаг нажатия кнопки скрипту нужно будет выйти из цикла работы с СОМ портом, установить флаг и вернуться обратно.  Если все-же необходимо не прерывать обработку данных с СОМ порта и работать одновременно с интерфейсом , тогда работу с СОМ портом можно вынести в отдельный скрипт (dll итп) и при необходимости из основного скрипта вызывать скрипт обработки данных.
Название: Re: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Январь 13, 2017, 16:00:48
Ведь даже , если устанавливать флаг нажатия кнопки скрипту нужно будет выйти из цикла работы с СОМ портом, установить флаг и вернуться обратно. 

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

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

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

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

 

Название: Re: Режим OnEvent и приоритетность
Отправлено: InnI от Январь 13, 2017, 16:17:05
VadimKHL
Цитировать
посылает запрос, и ожидает ответ
И сколько времени это занимает?
Название: Re: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Январь 13, 2017, 16:23:10
Все зависит от загруженности МК. Ответ может придти в интервале от 1 мс до 200 мс.
Название: Re: Режим OnEvent и приоритетность
Отправлено: InnI от Январь 13, 2017, 16:30:21
VadimKHL
Цитировать
до 200 мс
Для MessageLoop многовато... но попробовать можно. Тут зависит от того, как часто кнопки нажимаются и как быстро нужна реакция на нажатие.
В противном случае придётся делать гибрид - либо с флагами, либо с вкл/выкл режима.
Название: Re: Режим OnEvent и приоритетность
Отправлено: VadimKHL от Январь 13, 2017, 16:37:57
Накидал тестовую прогу.
OnEvent очень интересно работает.
он все события нажатия кнопок ставит в очередь. И это дает 100 процентов выполнения всех операций с GUI.
Для меня это самый правильный вариант.

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

Код: AutoIt [Выделить]
#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

Название: Re: Режим OnEvent и приоритетность
Отправлено: InnI от Январь 13, 2017, 17:04:35
VadimKHL
Цитировать
сгенерить события OnEvent программно, а не нажатием кнопки
Нужно просто программно нажать кнопку ;)
Код: AutoIt [Выделить]
AdlibRegister("BtnClick", 100)

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



Добавлено: Январь 13, 2017, 19:32:38
VadimKHL  [?]
Цитировать
OnEvent очень интересно работает.
он все события нажатия кнопок ставит в очередь
На самом деле очередь получается из-за того, что очередное событие не может прервать функцию, вызванную другим событием.

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

Вот вариант вашей "тестовой проги" в режиме MessageLoop (все события $GUI_EVENT_MOUSEMOVE вычищаются и интерфейс не тормозит)
(нажмите для показа/скрытия)
Название: Re: Режим OnEvent и приоритетность
Отправлено: Naisho от Январь 14, 2017, 14:55:49
Может так?

Код: AutoIt [Выделить]
#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