Описание GUI - режим MessageLoop (Цикл опроса GUI)

В режиме MessageLoop (цикла опроса GUI) ваш скрипт большую часть своего времени будет тратить в цикле. Этот цикл просто опрашивает GUI используя функцию GUIGetMsg. Когда произошло событие, функция GUIGetMsg возвращает значение (нажатие кнопки, закрытие GUI, и т.д.).

По умолчанию используется режим MessageLoop (цикл опроса GUI), другой возможный режим - OnEvent (по событию).

В режиме MessageLoop (цикла опроса GUI) вы получаете сообщения только в случае активного опроса элементов управления функцией GUIGetMsg, таким образом вы должны убедится, что вызываете функцию довольно часто (более 20-ти раз в секунду), иначе ваш GUI не будет откликаться на взаимодействие с элементами управления.


Основной формат MessageLoop (цикла опроса GUI)

Основной формат MessageLoop (цикла опроса GUI) выглядит так:

While 1
  $msg = GUIGetMsg()
  ...
  ...
WEnd


Обычно выполнение цикла приводит к загруженности процессора (CPU) до 100%, к счастью функция GUIGetMsg приводит процессор (CPU) в бездействие, при отсутствии ожидаемых событий. Не нужно самостоятельно вставлять функцию Sleep в цикл из-за страха перегрузить CPU, это только приведёт к тому, что GUI перестанет откликаться на взаимодействие с элементами управления.


События GUI

Существует три типа сообщения при событии, возвращаемых функцией GUIGetMsg:

  • Нет событий
  • Событие от элементов управления
  • Системное событие


  • Нет событий

    Если нет ожидаемых для обработки событий, то GUIGetMsg возвращает 0. Обычно в GUI это наиболее частый случай.


    Событие от элементов управления

    При клике на элементах управления или при их изменении, высылается сообщение, и оно является положительным числом, соответствующим идентификатору элемента управления controlID, возвращаемым функцией GUICtrlCreate... при создании элементов.


    Системное событие

    Системное событие - такое, как закрытие GUI - являются отрицательным числом. Разные события такого вида показаны ниже и их значения определены в GUIConstantsEx.au3:

    $GUI_EVENT_CLOSE
    $GUI_EVENT_MINIMIZE
    $GUI_EVENT_RESTORE
    $GUI_EVENT_MAXIMIZE
    $GUI_EVENT_PRIMARYDOWN
    $GUI_EVENT_PRIMARYUP
    $GUI_EVENT_SECONDARYDOWN
    $GUI_EVENT_SECONDARYUP
    $GUI_EVENT_MOUSEMOVE
    $GUI_EVENT_RESIZED
    $GUI_EVENT_DROPPED


    Пример GUI

    На главной странице Описание GUI мы начали делать простой пример "Привет Мир", который выглядел следующим образом:

    #include <GUIConstantsEx.au3>

    GUICreate("Привет Мир", 200, 100)
    GUICtrlCreateLabel("Привет Мир! Как дела?", 30, 10)
    GUICtrlCreateButton("OK", 70, 50, 60)
    GUISetState(@SW_SHOW)
    Sleep(2000)


    Теперь мы завершим код, используя режим MessageLoop (цикл опроса GUI) и некоторые сообщения от событий, описанных выше. Используем оператор Switch для удобочитаемости, это обычно из-за большого количества возможных сообщений.


    #include <GUIConstantsEx.au3>

    Local $hGUI = GUICreate("Привет Мир", 200, 100)
    GUICtrlCreateLabel("Привет Мир! Как дела?", 30, 10)
    Local $iOKButton = GUICtrlCreateButton("OK", 70, 50, 60)
    GUISetState(@SW_SHOW, $hGUI)

    Local $iMsg
    While 1
        $iMsg = GUIGetMsg()
        Switch $iMsg
            Case $iOKButton
                MsgBox(0, "Событие GUI", "Вы нажали OK!")

            Case $GUI_EVENT_CLOSE
                MsgBox(0, "Событие GUI", "Вы нажали ЗАКРЫТЬ ! Завершаем...")
                ExitLoop
        EndSwitch
    WEnd


    GUIDelete($hGUI)

    Это очень простой пример. Очевидно, что чем больше окон и элементов управления вы используете, тем сложнее он становится, но выше указанное показывает вам основу.


    Расширенный GUIGetMsg и многооконный интерфейс

    Идентификатор элементов управления (ID) являются уникальным, даже если у вас есть несколько окон, поэтому вышеприведенный код прекрасно работает с элементами управления и с несколькими окнами.  Тем не менее, при обработке событий таких как $GUI_EVENT_CLOSE или $GUI_MOUSEMOVE вы должны знать, какое GUI-окно вызвало событие.  Для этого вы должны вызвать GUIGetMsg таким образом:

    $aMsg = GUIGetMsg(1)


    При вызове с параметром 1 вместо возвращаемого события возвращается массив, который содержит событие (в $aMsg[0]), а также дополнительную информацию, например, дескриптор окна (в $aMsg[1]).  Если бы два окна были созданы в предыдущем примере, то правильный способ написания кода будет выглядеть так:

    #include <GUIConstantsEx.au3>

    Local $hMainGUI = GUICreate("Привет Мир", 200, 100)
    GUICtrlCreateLabel("Привет Мир! Как дела?", 30, 10)
    Local $iOKButton = GUICtrlCreateButton("OK", 70, 50, 60)

    Local $hDummyGUI = GUICreate("Окно для теста", 200, 100)

    GUISwitch($hMainGUI)
    GUISetState(@SW_SHOW)

    Local $aMsg
    While 1
        $aMsg = GUIGetMsg(1)

        Select
            Case $aMsg[0] = $iOKButton
                MsgBox(0, "Событие GUI", "Вы нажали OK!")

            Case $aMsg[0] = $GUI_EVENT_CLOSE And $aMsg[1] = $hMainGUI
                MsgBox(0, "Событие GUI", "Вы нажали ЗАКРЫТЬ в главном окне! Завершаем...")
                ExitLoop
        EndSelect
    WEnd


    Первым заметным изменением является вызов функции GUISwitch - когда создается новое окно, оно становится "по умолчанию" для будущих операций с GUI (в том числе создание элементов управления).  В нашем случае мы хотим работать с главным окном "Привет Мир", а не в тестовом окне, таким образом мы "переключаем". Некоторые функции GUI позволяют использовать дескриптор окна в своих параметрах - эти функции переключают автоматически. В нашем примере мы можем сделать это с помощью:

    GUISetState(@SW_SHOW, $mainwindow)


    Следующим различием является способ вызова GUIGetMsg для проверки событий - заметьте использование $aMsg[0] и $aMsg[1] - теперь у нас единственный способ завершить скрипт, если произойдёт событие выхода и это событие вызвано из нашего основного окна скрипта.