在消息循环模式下, 脚本大部分时间都在执行一个周期非常短的循环,这个循环通知 GUI 使用 GUIGetMsg 函数截获消息.
当某个消息发生时, GUIGetMsg 函数的返回值将显示消息的详细信息(如按钮点击, GUI 关闭, 等等.).
该 MessageLoop 模式是 AutoIt 默认 GUI 模式 - 另一个模式是 OnEvent 事件模式.
在消息模式下, 只有频繁调用 GUIGetMsg 函数才有可能接收到消息,
因此您必须确保每秒时间内多次调用该函数,否则您的 GUI 将无法响应消息.
下面是消息循环的基本结构代码:
While 1
$msg = GUIGetMsg()
...
...
WEnd
像上面这种循环周期非常短的脚本通常会把 CPU 占用推高到 100%,
幸运的是 GUIGetMsg 函数可在无消息时自动闲置 CPU.
另外千万不要因为怕增加 CPU 的压力而自己添加休眠语句(Sleep)到脚本中,这么做只会让 GUI 响应迟钝.
GUIGetMsg 返回的消息消息有以下三种:
无消息
没有截获任何消息时, GUIGetMsg 的返回值为 0.这也是 最常发生的消息
控件消息
当某个控件被点击或该控件有其它变化时将发送控件消息. 这些消息代码都是正数, 并且关联发送消息的控件ID.
(也即使用 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 概论 页面上我们曾编写过一个简单的窗口:
#include <GUIConstantsEx.au3>
GUICreate("您好,世界", 200, 100)
GUICtrlCreateLabel("您好,世界! 你过得怎么样?", 30, 10)
GUICtrlCreateButton("确定", 70, 50, 60)
GUISetState(@SW_SHOW)
Sleep(2000)
现在我们来尝试使用消息循环以及上面描述的消息来完成全部代码.
出于脚本的可读性考虑, 我们使用 Select 条件选择语句:
#include <GUIConstantsEx.au3>
GUICreate("您好,世界", 200, 100)
GUICtrlCreateLabel("您好,世界! 你过得怎么样?", 30, 10)
$okbutton = GUICtrlCreateButton("确定", 70, 50, 60)
GUISetState(@SW_SHOW)
While 1
$msg = GUIGetMsg()
Select
Case $msg = $okbutton
MsgBox(0, "GUI 消息", "你点击了
'确定'!")
Case $msg = $GUI_EVENT_CLOSE
MsgBox(0, "GUI 消息",
"您选择了关闭窗口!正在退出...")
ExitLoop
EndSelect
WEnd
就这么简单. 很明显的, 创建的窗口及控件越多则脚本越复杂, 但基本结构都是类似上面的这个示例.
即使有多窗口存在, 控件 ID 也是唯一的. 因此上面的脚本也能在多窗口环境中正常工作.
但是在处理如 $GUI_EVENT_CLOSE(窗口关闭) 或 $GUI_MOUSEMOVE(鼠标移动) 等消息时,
您还必须知道究竟是哪个窗口引发的消息. 为了解决这个问题, 您可以参考下面这个语句来调用 GUIGetMsg 函数
$msg = GUIGetMsg(1)
当调用函数 GUIGetMsg 指定参数 1, 则它将返回一个数组而不是消息值,
这个数组不仅包括被截获的消息(保存在$array[0]中), 还包括其它信息, 如窗口句柄等(保存在$array[1]中).
假设我们要创建两个窗口, 则相应的脚本代码如下:
#include <GUIConstantsEx.au3>
$mainwindow = GUICreate("您好,世界", 200, 100)
GUICtrlCreateLabel("您好,世界! 你过得怎么样?", 30, 10)
$okbutton = GUICtrlCreateButton("确定", 70, 50, 60)
$dummywindow = GUICreate("用于测试用虚拟窗口,不会显示 ", 200, 100)
GUISwitch($mainwindow)
GUISetState(@SW_SHOW)
While 1
$msg = GUIGetMsg(1)
Select
Case $msg[0] = $okbutton
MsgBox(0, "GUI 消息", "你点击了
'确定'!")
Case $msg[0] = $GUI_EVENT_CLOSE And $msg[1] =
$mainwindow
MsgBox(0, "GUI 消息",
"您选择了关闭主窗口!正在退出...")
ExitLoop
EndSelect
WEnd
第一个主要的变化是 GUISwitch 函数的调用.
当新的窗口被创建之后, 该窗口即成为后面所有 GUI 操作(包括创建控件)的“默认”工作窗口,
也就是说这些 GUI 操作的对象都会是这个默认窗口.
现在要处理的是"您好,世界"的窗口, 而不是那个虚拟测试窗口, 这时就要使用 GUISwitch 函数来切换操作对象.
某些 GUI 函数允许调用时使用窗口句柄指定操作目标, 同时也将自动切换该目标窗口为"默认窗口".
所以在这个示例中, 我们可以改用这样的语句:
GUISetState(@SW_SHOW, $mainwindow)
下一个变化是 GUIGetMsg 函数的用法以及消息是如何被截获并处理的.注意脚本中 $msg[0] 和 $msg[1] 的用法.
现在可以确保窗口关闭按钮被点击的消息是从主窗口发送的时候才退出 GUI 了.
provider with jb51.net (unicode) |