GUI 相关 - OnEvent 模式

在 OnEvent(事件驱动)模式下,脚本并不需要频繁地要求GUI检查是否有任何事件发生(并根据返回信息处理事件),而是仅当某个事件发生时GUI才临时性暂停脚本并调用一个用户预定义的函数来处理该事件。例如,假定用户点击了按钮1则GUI将暂停主脚本并调用某个预定义的用户函数来处理按钮1事件。当该函数完成处理操作后才回到主脚本继续执行。这个模式比较类似 Visual Basic 的窗体方法。

当GUI被执行时,主脚本还可以做其它一般性工作,但为了演示方便我们只是让主脚本在一个无限While循环里“睡眠”一下。

因为消息循环是默认的模式,所以在应用 OnEvent 模式之前我们应该先使用 Opt("GUIOnEventMode", 1) 语句。

 

基本的 OnEvent 结构

下面是 OnEvent 的基本结构:

While 1
  Sleep(1000)   ; 闲置工作,不做任何事
WEnd
  
Func Event1()
  ; 处理事件的代码放在这里
EndFunc

Func Event2()
  ; 处理事件的代码放在这里
EndFunc

 

GUI 事件

在 OnEvent 模式下会产生两种“事件”:

  • 控件事件
  • 系统事件
  •  

    这两种事件类型发生时都将调用用户预先定义的函数,这些函数可以是为GUI(窗口)设置的(GUISetOnEvent)或者为控件设置的(GUICtrlSetOnEvent)。如果某事件并没有预先定义相应的处理函数则该事件将被忽略。在这些被调用的函数内部可使用各种 宏 以助处理事件:

    说明
    @GUI_CTRLID 发送消息的控件ID 或者 系统事件ID
    @GUI_WINHANDLE 发送消息的GUI(窗口)句柄
    @GUI_CTRLHANDLE 发送消息的控件句柄(如果适用)

    注意:使用同一个函数来响应多种事件是完全合法的,记住要灵活使用 @GUI_CTRLID 这个宏。比如说,您可以注册所有系统事件到同一个函数。

     

    控件

    当某个控件被点击或该控件有其它变化时将发送控件事件。该事件将被传递到由 GUICtrlSetOnEvent 定义的函数中。在这个函数里,@GUI_CTRLID 的值是发送消息的 控件ID(也即使用 GUICtrlCreate... 函数创建该控件时的返回值)。

     

    系统事件

    系统事件包括GUI(窗口)被关闭等在内,它们以类似于控件事件的方式被发送出去,而事件类型(ID)则由 @GUI_CTRLID 指示。系统事件将被传递到由 GUISetOnEvent 定义的函数中。可能的系统事件包括:

    $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 示例

    GUI 相关 的页面上我们曾编写过一个简单的窗口:

    #include <GUIConstants.au3>

    GUICreate("您好", 200, 100)
    GUICtrlCreateLabel("最近过得怎样?", 30, 10)
    GUICtrlCreateButton("还OK吧", 70, 50, 60)
    GUISetState(@SW_SHOW)
    Sleep(2000)

     

    现在我们来尝试使用 OnEvent 以及上面描述的事件消息来完成全部代码:

     

    #include <GUIConstants.au3>

    Opt("GUIOnEventMode", 1)  ; 切换为 OnEvent 模式
    $mainwindow = GUICreate("您好", 200, 100) ; 创建窗口并返回窗口句柄
    GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked") ; 设置窗口关闭事件
    GUICtrlCreateLabel("最近过得怎样?", 30, 10)
    $okbutton = GUICtrlCreateButton("还OK吧", 70, 50, 60)
    GUICtrlSetOnEvent($okbutton, "OKButton")
    GUISetState(@SW_SHOW)

    While 1
      Sleep(1000)  ; 不做任何事
    WEnd

    Func OKButton()
      ;注意:此时 @GUI_CTRLID 的值将等价于 $okbutton,
      ;而 @GUI_WINHANDLE 则等价于 $mainwindow
      MsgBox(0, "GUI 事件", "您按下了“还OK吧”按钮!")
    EndFunc

    Func CLOSEClicked()
      ;注意:此时 @GUI_CTRLID 的值将等价于 $GUI_EVENT_CLOSE,
      ;而 @GUI_WINHANDLE 则等价于 $mainwindow
      MsgBox(0, "GUI 事件", "您选择了关闭!正在退出...")
      Exit
    EndFunc

    很简单,对吧?很明显创建的窗口及控件越多则脚本越复杂,但基本结构都是类似上面的这个示例。

     

    高级操作及多窗口

    即使有很多窗口存在,控件 ID 也是唯一的,但是我们如何处理多窗口呢?

    下面这个示例脚本和上面的很像,但多出了一个“dummy(虚设的)”窗口。

    #include <GUIConstants.au3>

    Opt("GUIOnEventMode", 1)  ; 切换为 OnEvent 模式
    $mainwindow = GUICreate("您好", 200, 100)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
    GUICtrlCreateLabel("最近过得怎样?", 30, 10)
    $okbutton = GUICtrlCreateButton("还OK吧", 70, 50, 60)
    GUICtrlSetOnEvent($okbutton, "OKButton")

    $dummywindow = GUICreate(" 这只是测试用的虚设窗口,并不会被显示 ", 200, 100)
    GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")

    GUISwitch($mainwindow)
    GUISetState(@SW_SHOW)

    While 1
      Sleep(1000)  ; 不做任何事
    WEnd

    Func OKButton()
      ;注意:此时 @GUI_CTRLID 的值将等价于 $okbutton
      MsgBox(0, "GUI 事件", "您按下了“还OK吧”按钮!")
    EndFunc

    Func CLOSEClicked()
      ;注意:此时 @GUI_CTRLID 的值将等价于 $GUI_EVENT_CLOSE,
      ;而 @GUI_WINHANDLE 则等价于 $mainwindow 或 $dummywindow
      If @GUI_WINHANDLE = $mainwindow Then
        MsgBox(0, "GUI 事件", "您选择了关闭主窗口!正在退出...")
        Exit
      EndIf
    EndFunc

     

    第一个需要注意的变动是上面的脚本增加了一个 GUISwitch 函数的调用,当新的窗口被创建之后该窗口即变成后面所有GUI操作(包括创建控件在内)的“默认”窗口,也就是说这些GUI操作的对象都会是这个默认窗口。但我们希望显示的是主窗口(首先被创建的窗口)而不是那个测试窗口,这时就要使用 GUISwitch 函数来切换操作对象。某些GUI函数允许您在调用它们时使用窗口句柄(参数)来指定操作目标,同时也将自动切换该目标窗口为“默认窗口”。所以在这个示例中,我们还可以改用这样的语句:

    GUISetState(@SW_SHOW, $mainwindow)

     

    另外要注意的就是我们使用了同一个 OnEvent 函数来处理两个窗口的“关闭”事件,为了识别被关闭的窗口究竟是哪一个我们还使用了 @GUI_WINHANDLE 来检查发送消息的窗口句柄。这样处理之后我们就可以确保在窗口的关闭按钮被点击 而且 消息是从主窗口发送的时候才退出GUI了。当然了,您也可以为每个窗口指定不同的事件处理函数。