AutoIt 入门与提高 第二章窗口

2010-06-02  刘旸 

转载自: http://crossdoor.cublog.cn/
大致看了一下,写的非常好。看来偶只是入门了而已。
有学习 autoit的朋友,可以看一看。

第二章窗口
作为一个多任务操作系统,Windows 可以同时运行多个程序。有些程序在后
台运行,不需要像使用者显示信息,例如系统服务程序;有些程序则需要接受用
户的输入信息,并处理后输出,例如计算器。
为了接收用户输入的信息,以及向用户输出处理的结果,程序就必须建立一
个窗口来完成此项任务。
窗口有一个重要的属性,就是句柄。为了区别不同的窗口,从而达到结果输
出不会混淆的目的,Windows 系统给每个窗口都分配了一个唯一的句柄。通过这
个句柄我们可以操作自己建立的窗口,也可以操作其它程序建立的窗口,也就是
AutoIt 擅长的自动化操作(这里不讲自动化操作)。
这一章我们来学习如何使用AutoIt 建立窗口。
1、第一个窗口程序
创建一个空白的窗口:(把下面的代码复制到SCITE 编辑器中,然后保存文件。遇到不懂的
函数可以把光标移动函数中间,然后按F1 获取帮助。)
Global Const $GUI_EVENT_CLOSE = -3;窗口关闭消息的值
GUICreate("我的第一个窗口") ; 创建一个居中显示的GUI 窗口
GUISetState(@SW_SHOW) ; 显示一个空白的窗口
While 1
$msg = GUIGetMsg();捕获窗口消息
If $msg = $GUI_EVENT_CLOSE Then ExitLoop;使用关键字ExitLoop 跳出While 循环
WEnd
GUIDelete();删除窗口界面
注意:ExitLoop 关键字是用来跳出循环的。While、Do、For 循环都可以使用它来跳出。当多层循环嵌
套时,它除了能跳出最近一层的循环外,还可以跳出外层的任意一层循环,后面接一个数字,表示第几层
循环(后面没跟数字时,表示使用默认值1,跳出最靠近它的循环)。
一个完整的窗口,还应该包括一些控件,比如输入框、按钮之类的。与窗口
一样,这些控件也有句柄,我们称为控件句柄,对控件的操作则通过这些句柄来
进行。
因为窗口程序时通过事件驱动,例如按下最小化按钮、关闭按钮等。用户对
窗口进行的任何一个操作,都会产生一个消息。Windows 系统根据不同的消息,
来响应不同的操作。
程序运行期间会不断的产生消息,为了不错过这些消息我们有两种方式来处
理。一种是不断的循环消息,已达到不错过的目的;还有一种是使用Event 模式,
当产生事件时就进行响应。
AutoIt 入门与提高
crossdoor Page 20 6/2/2010
1.1、窗口消息
首先我们来看一下消息循环模式:
Global Const $GUI_EVENT_CLOSE = -3;窗口关闭消息的值
GUICreate("我的第一个窗口") ; 创建一个居中显示的GUI 窗口
$Input = GUICtrlCreateInput("1111", 10, 35, 300, 20)
$btn = GUICtrlCreateButton("读取输入框", 40, 75, 90, 20)
GUISetState(@SW_SHOW) ; 显示一个空白的窗口
While 1 ;死循环,直到捕获窗口的退出消息才跳出
$msg = GUIGetMsg();捕获窗口消息
Select;使用分支判断窗口消息
Case $msg = $GUI_EVENT_CLOSE;退出消息
ExitLoop
Case $msg = $btn;按钮被点击
$D = GUICtrlRead($Input);读取输入框数据
MsgBox(0, "输入框的数据", $D)
EndSelect
WEnd
GUIDelete();删除窗口界面
从上例可以看出,消息循环模式时,脚本处于一个死循环中,并且在循环里
不断的捕获窗口上产生的消息,然后再根据消息来进行操作。
这种模式是一直在被动的不断获取窗口的消息,在系统资源的耗费上相当的
不划算。而且因为脚本的主循环需要不断的处理消息,使得我们想要在主循环中
执行其它代码很不方便。因为这样很容易造成消息无法得到及时的响应。
AutoIt 入门与提高
crossdoor Page 21 6/2/2010
接着来看一下Event 模式:
Global Const $GUI_EVENT_CLOSE = -3;窗口关闭消息的值
Opt("GUIOnEventMode", 1) ;开启Event 模式
GUICreate("我的第一个窗口") ; 创建一个居中显示的GUI 窗口
GUISetOnEvent($GUI_EVENT_CLOSE, "main");注册关闭消息到自定义函数main 里面进行处理
$Input = GUICtrlCreateInput("1111", 10, 35, 300, 20)
$btn = GUICtrlCreateButton("读取输入框", 40, 75, 90, 20)
GUICtrlSetOnEvent($btn, "main");注册按钮点击消息到自定义函数main 里面进行处理
GUISetState(@SW_SHOW) ; 显示一个空白的窗口
While 1 ;死循环,保证脚本不会退出
GUISetBkColor(RandomColor());修改窗口背景颜色
Sleep(3000) ;睡眠3 秒
WEnd
Func main()
Switch @GUI_CtrlId;根据宏@GUI_CtrlId 来判断消息
Case $GUI_EVENT_CLOSE
Exit
Case $btn
$D = GUICtrlRead($Input);读取输入框数据
MsgBox(0, "输入框的数据", $D)
EndSwitch
EndFunc
Func RandomColor()
Return "0x" & Hex(Random(0, 255, 1), 2) & Hex(Random(0, 255, 1), 2) &
Hex(Random(0, 255, 1), 2)
EndFunc ;产生一个随机的RGB 颜色值
从上例可以看出,Event 模式时,当窗口产生消息时,才会对消息进行响应,
而不会一直处于消息检测状态。这样一来,相较于消息循环模式将会节省大量的
CPU。
而且在主循环中,我们还可以做其它的事情,而不用担心会造成消息的延迟。
(如果在消息循环模式下,主循环也睡眠3 秒的话,那窗口的消息将会被延迟甚
至不响应。)
所以我推荐大家在处理窗口消息时,要尽量使用Event 模式。
1.2、消息拦截
AutoIt 提供了一个内置函数GUIRegisterMsg,可以让我们为已知Windows 消
息代码(WM_MSG)注册一个自定义的函数来进行操作。
AutoIt 入门与提高
crossdoor Page 22 6/2/2010
具体的使用我们来看实例:
Global Const $GUI_EVENT_CLOSE = -3;窗口关闭消息的值
Global Const $WM_ENTERSIZEMOVE = 0x0231;窗口移动消息的值
Global Const $WM_EXITSIZEMOVE = 0x0232;窗口结束移动消息的值
Opt("GUIOnEventMode", 1) ;开启Event 模式
$Gui = GUICreate("我的第一个窗口") ; 创建一个居中显示的GUI 窗口
GUISetOnEvent($GUI_EVENT_CLOSE, "main");注册关闭消息到自定义函数main 里面进行处理
$Input = GUICtrlCreateInput("1111", 10, 35, 300, 20)
$btn = GUICtrlCreateButton("读取输入框", 40, 75, 90, 20)
GUICtrlSetOnEvent($btn, "main");注册按钮点击消息到自定义函数main 里面进行处理
GUISetState(@SW_SHOW) ; 显示一个空白的窗口
GUIRegisterMsg($WM_ENTERSIZEMOVE, "WM_ENTERSIZEMOVE");产生窗口移动消息时,执行
自定义函数WM_ENTERSIZEMOVE
GUIRegisterMsg($WM_EXITSIZEMOVE, "WM_EXITSIZEMOVE");窗口移动结束时,执行自定义函
数WM_EXITSIZEMOVE
While 1 ;死循环,保证脚本不会退出
GUISetBkColor(RandomColor());修改窗口背景颜色
Sleep(3000) ;睡眠3 秒
WEnd
Func main()
Switch @GUI_CtrlId;根据宏@GUI_CtrlId 来判断消息
Case $GUI_EVENT_CLOSE
Exit
Case $btn
$D = GUICtrlRead($Input);读取输入框数据
MsgBox(0, "输入框的数据", $D)
EndSwitch
EndFunc
Func RandomColor()
Return "0x" & Hex(Random(0, 255, 1), 2) & Hex(Random(0, 255, 1), 2) &
Hex(Random(0, 255, 1), 2)
EndFunc ;产生一个随机的RGB 颜色值
Func WM_ENTERSIZEMOVE($hWndGUI, $MsgID, $WParam, $LParam)
WinSetTrans($Gui, "", 130)
EndFunc ;窗口移动时,设置窗口透明值为130
Func WM_EXITSIZEMOVE($hWndGUI, $MsgID, $WParam, $LParam)
WinSetTrans($Gui, "", 255)
EndFunc ; 窗口结束移动时,设置窗口透明值为255,也就是不透明
上面的代码运行后,当窗口移动时,你会发现窗口变成半透明的了,这是因
AutoIt 入门与提高
crossdoor Page 23 6/2/2010
为脚本把窗口移动的消息拦截下来了,在发生移动的时候,脚本把窗口设置成了
半透明。除此以外,我们还可以拦截其它的消息,比如列表控件的双击、单击消
息,组合列表框控件的点击、选择消息等。
对于自己编写的程序的窗口,我们可以使用此种方法来拦截消息。但是对于
外部程序的窗口则不能这样做,若非要拦截外部程序窗口的消息,唯一的方法就
是注入到目标程序的进程中去。此处不讨论这些,略过。
2、多窗口程序
在实际的应用中,程序可能需要用到多窗口来实现,典型的例子就是QQ,
除了主界面之外,还有聊天窗口、资料设置窗口、好友查找窗口等。
窗口与窗口之间的关系除了平等之外,还有父子窗口。也就是以其中一个窗
口为主窗口,其余窗口均为主窗口的下属窗口。平等关系的我们就不说了,因为
跟父子窗口差不多,所以我们就说一下父子窗口好了。
2.1、父窗口与子窗口
AutoIt 内置的窗口创建函数GUICreate 有八个参数,通过查看帮助,我们
可以看到,最后一个参数可以为新建的窗口指定父窗口的句柄,这样一来新窗口
就将成为一个子窗口。
如果窗口需要指定样式,比如去掉关闭按钮、去掉最小化按钮等等,也可以
在使用GUICreate 创建时一并设置。GUICreate 函数的第六和第七两个参数
就是设置窗口样式的,至于具体的样式我们可以查看帮助。如果要使用默认样式
可以设置为-1。
GUICreate 函数创建窗口成功后将会返回一个真正的句柄。为什么要这么
说呢?这是因为AutoIt 在创建控件时,返回的并不是真正的控件句柄,而是控
件标识,所谓标识就是一个整数。
也就是说,如果你在窗口上创建了十个按钮,那么这十个按钮返回的并非是
按钮控件的句柄,而是一到十的十个整数。(这里只是举例,实际应用中可能并
非刚好是一到十。)
要取得控件的真正句柄,我们需要用到GUICtrlGetHandle 这个函数,此
函数可以根据控件标识返回控件句柄。
以上这些在此只是顺带说明,不做具体的实例说明。本小节我们还是以父窗
口和子窗口为主题。
关于父窗口与子窗口的应用我们来看一段实例:
AutoIt 入门与提高
crossdoor Page 24 6/2/2010
Global Const $GUI_EVENT_CLOSE = -3;窗口关闭消息的值
Dim $Child_Gui;定义一个变量用于存放子窗口的句柄
Opt("GUIOnEventMode", 1) ;开启Event 模式
$Gui = GUICreate("我的第一个窗口") ; 创建一个居中显示的GUI 窗口
GUISetOnEvent($GUI_EVENT_CLOSE, "main");注册关闭消息到自定义函数main 里面进行处理
$Input = GUICtrlCreateInput("1111", 10, 35, 300, 20)
$btn = GUICtrlCreateButton("读取输入框", 40, 75, 90, 20)
GUICtrlSetOnEvent($btn, "main")
$Show_btn = GUICtrlCreateButton("显示子窗口", 40, 100, 90, 20)
GUICtrlSetOnEvent($Show_btn, "main")
GUISetState(@SW_SHOW) ; 显示一个空白的窗口
While 1 ;死循环,保证脚本不会退出
GUISetBkColor(RandomColor());修改窗口背景颜色
Sleep(1000)
WEnd
Func main()
Switch @GUI_CtrlId;根据宏@GUI_CtrlId 来判断消息
Case $GUI_EVENT_CLOSE
Switch @GUI_WinHandle;根据宏@GUI_WinHandle 来判断产生关闭消息的窗口消息
Case $GUI
Exit
Case $Child_Gui
GUIDelete($Child_Gui)
EndSwitch
Case $btn
$D = GUICtrlRead($Input);读取输入框数据
MsgBox(0, "输入框的数据", $D)
Case $Show_btn
Child_Gui ()
EndSwitch
EndFunc
Func RandomColor()
Return "0x" & Hex(Random(0, 255, 1), 2) & Hex(Random(0, 255, 1), 2) &
Hex(Random(0, 255, 1), 2)
EndFunc ;产生一个随机的RGB 颜色值
Func Child_Gui ()
$Child_Gui = GUICreate("我是子窗口", 200, 40, -1, -1, -1, -1, $Gui)
GUISetOnEvent($GUI_EVENT_CLOSE, "main")
GUISetState(@SW_SHOW)
EndFunc ;子窗口
AutoIt 入门与提高
crossdoor Page 25 6/2/2010
细心的朋友肯定会发现,在自定义函数中我们嵌套使用了两个分支判断语句
Switch。扩展一下,我们还可以在分支判断语句里面使用循环语句While,而
且循环语句内还可以再使用循环语句,具体的使用,大家可以自己写代码熟悉一
下。
在上面的代码中,当子窗口显示后,主窗口的背景色将保持不变,转而是子
窗口的背景色被不断修改。造成这个现象的原因在于GUISetBkColor 函数,查看
帮助可以看到这个函数有两个参数,其中第二个参数是需要操作的窗口的句柄,
这个参数是可以省略的。
在省略状况下,函数将会使用最近一次使用过的窗口句柄。当子窗口出现时,
最近一次使用的窗口句柄变成了子窗口的,所以背景颜色被改变的窗口就从父窗
口变成了子窗口。
2.2、GUI 嵌入外部进程窗口
除了上节中说明的父子窗口,还有一种特殊的父子窗口。玩过网游的朋友肯
定会发现,游戏界面内部的窗口,无论如何都不能被移除游戏界面之外。就像是
一个窗口被镶嵌在另一个窗口内部,无法取出一样。
AutoIt 可以使用API 来达成这种效果,此处我们只演示一下这种效果,不对
API 的调用做详细的解释,等到后文会有具体的说明章节。
我们来看实例代码:(窗口一个窗口,然后嵌入到记事本中)
Run("notepad.exe") ;运行记事本
WinWait("无标题- 记事本") ;等待记事本窗口出现
$Gui = GuiCreate("被装进了记事本", 240, 120)
GuiSetState()
DllCall("user32.dll", "int", "SetParent", "hwnd", $Gui, "hwnd",WinGetHandle("无
标题- 记事本")) ;使用API 把脚步建立的窗口嵌入记事本窗口中
Do
;Do 循环,当窗口消息等于退出消息,或者记事本窗口消失时,就退出循环
Until GuiGetMsg() =-3 Or Not WinExists("无标题- 记事本")
上面的代码只是创建了一个空白的窗口嵌入到记事本窗口中,实际的运用还
要看具体的目的。比如说在全屏游戏时,嵌入一个窗口来显示当前时间,这样就
可以不用切换到桌面来查看时间。
876°/8766 人阅读/0 条评论 发表评论

登录 后发表评论