[已解决]跳出FOR循环难题
本帖最后由 dnbj2010 于 2011-10-21 09:00 编辑下面的例子,逐字对比两段数据,并在脚本下方气泡提示发现不同的次数。
使用了一个FOR循环来完成数据比较,但之后发现停止按扭无法中止循环。
改用$WM_COMMAND截取按钮消息,还是无法跳出循环。
再添加一个定时器,在定时器启动的事件中,加强对按钮消息的监测,但还是无法跳出循环。
使用热键可以退出,本例Esc即是跳出热键。
但还是想通过点击按钮来跳出循环。
参看了许多坛友的贴子,发现在循环数据处理量不大的情况下,可能有效,但如果在循环时处理的数据量比较频密,则大多失效。
要注意的是,如果为了使截取的按钮消息起到作用,而降低循环的数据处理速度,那过低的数据处理速度可能没什么意义了
如本例,还不如用眼睛一行一行看呢。
请高人指点
测试代码如下:#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
Opt("GUIOnEventMode", 1) ; 切换为 OnEvent 模式
HotKeySet("{Esc}", "tingzhi") ;热键设置停止循环
Dim $a,$x,$i,$d,$tt,$dll,$Timer,$TimerDLL,$tm ,$tip,$Pm
$Form1 = GUICreate("Form1", 820, 620, 100, 50)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
$Edit1 = GUICtrlCreateEdit("", 5, 64, 401, 550,$ES_WANTRETURN)
$Edit2 = GUICtrlCreateEdit("", 415, 64, 401, 550,$ES_WANTRETURN)
;BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))
;-------------------------
$filetext1 = "数据不够自行复制粘贴5B30303039434645435D204C6F6164696E6720446576696365203D2048494D454D2E5359530D0A284C6F676F2064" & _
"697361626C6564290D0A5B30303039434645435D204C6F616453756363657373202020203D2048494D454D2E5359530D0A5B3" & _
"720446576696365203D20474344524F4D2E5359530D0A5B30303039443033375D204C6F61644661696C656420202020203D2047" & _
"0303039434645435D204C6F6164696E6720446576696365203D20514344524F4D2E5359530D0A5B30303039434645445D204C6" & _
"F61645375636365737320202"
$filetext2 = "数据不够自行复制粘贴5B30303039434646465D204C6F6164696E6720446576696365203D20474344524F4D2E5359530D0A5B30303039443" & _
"031335D204C6F61644661696C656420202020203D20474344524F4D2E5359530D0A5B30303039443032335D204C6F6164696E6" & _
"0303039434645435D204C6F6164696E6720446576696365203D20514344524F4D2E5359530D0A5B30303039434645445D204C6" & _
"720446576696365203D20474344524F4D2E5359530D0A5B30303039443033375D204C6F61644661696C656420202020203D2047" & _
"4344524F4D2E5359530D0A"
GUICtrlSetData($Edit1,$filetext1)
GUICtrlSetData($Edit2,$filetext2)
ControlFocus ("Form1","",$Edit1)
Send("^{Home}")
;--------------------------
$Button1 = GUICtrlCreateButton("比较", 5, 16, 75, 25)
$Button2 = GUICtrlCreateButton("停止", 105, 16, 75, 25)
GUICtrlSetOnEvent($Button1, "huoquData1")
GUICtrlSetOnEvent($Button2, "tingzhi")
;-----------------------------------------------
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
;AdlibRegister( "detect",250);自定义监控函数
GUISetState(@SW_SHOW)
While 1
Sleep(1)
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Func huoquData1()
$x = 0 ;循环启动标识
$tt = 0 ;循环运行标识
$tm = 0
$tip = 0
;AdlibRegister( "detect",250) ;自定义监控函数,此函数的问题是,不可以取消事件,考虑用定时器
If $tt = 0 Then
$dll = DllOpen("user32.dll")
$Timer = DllCallbackRegister("Timer", "int", "hwnd;uint;uint;dword")
$TimerDLL = DllCall($dll, "uint", "SetTimer", "hwnd", 0, "uint", 0, "int", 10, "ptr", DllCallbackGetPtr($Timer))
EndIf
$GetData1 = GUICtrlRead ($Edit1)
$GetData2 = GUICtrlRead ($Edit2)
$RightDataA = StringLen($GetData1) ;最后一个字符的位置
$a = 0
$d = $RightDataA
For $i =1 To $d Step 1
Sleep(100)
If $x = 1 Then
$tt = 1
Return
EndIf
$a = $a + 1
;-------------移动------
ControlFocus ("Form1","",$Edit1)
If $a-1 = 0 Then Send("^{Home}")
Send("{RIGHT " & $a-1 & "}") ; 移动插入点前位置
;-------------移动------
If $x = 1 Then
$tt = 1
Return
EndIf
$MidDataA = StringMid ($GetData1,$a,1)
$MidDataB = StringMid ($GetData2,$a,1)
$ComData = StringCompare ($MidDataA,$MidDataB,1) ;比较两个数值
If $x = 1 Then Return
If $ComData <> 0 Then
$tip = $tip + 1
TrayTip("循环中","发现" & $tip &"处不同",10, 1)
If $x = 1 Then
$tt = 1
Return
EndIf
EndIf
If $x = 1 Then
$tt = 1
Return
EndIf
Next
EndFunc
Func tingzhi()
$x = 1
EndFunc
Func CLOSEClicked()
GUIDelete()
Exit
EndFunc
Func WM_COMMAND($hWnd, $Msg, $wParam, $lParam)
If $lParam = GUICtrlGetHandle($Button2) Then $Pm = 1
If $x = 0 And $lParam = GUICtrlGetHandle($Button2) Then
$x = 1
EndIf
EndFunc
Func Timer($hWnd, $uiMsg, $idEvent, $dwTime)
If $x = 0 And $Pm = 1 Then
$x = 1
EndIf
If $tm = 0Then
If $x = 1 Then
$tm = 1 ;不进行二次操作
;MsgBox(0,"","测试",1)
timeclose() ;关闭定时器
EndIf
Else
EndIf
EndFunc
Func timeclose()
DllCall($dll, "int", "KillTimer", "hwnd", 0, "uint", $TimerDLL)
DllCallbackFree($Timer)
DllClose($dll)
MsgBox(0,"","FOR循环已停止!")
EndFunc
呵呵,自问自答一下吧。
热键通过键盘发送指令,按钮通过鼠标发送指令。
按钮事件与键盘事件的一个不同之处就是:系统要多一个判断按钮状态的持续性的步骤。
如果由于某种原因,干扰了系统获取按钮的状态,那么即使设置了截取按钮消息也应该是无用了,嗯,有门。
这是因为FOR循环对资源的占用吗?
按钮状态未按与已按,不就是获得了键盘焦点吗?
突然想起帮助文档里似乎有一个判断控件焦点状态的函数,赶紧翻一下看。
果然,
ControlGetFocus 返回指定窗口上键盘焦点所在的控件的类别名.
汗,这个函数居然忘了。
把这个函数放到定时器里,分分钟监控按钮的动作,应该可以的。
改动定时器内的代码:Func Timer($hWnd, $uiMsg, $idEvent, $dwTime)
If ControlGetFocus ("Form1") = "Button2" Then ;返回指定窗口上键盘焦点所在的控件的类别名.
$x = 1
EndIf
If $tm = 0Then
If $x = 1 Then
$tm = 1 ;不进行二次操作
;MsgBox(0,"","测试",1)
timeclose() ;关闭定时器
EndIf
Else
EndIf
EndFunc 测试后,还是不行啊,按钮的一瞬间,光标闪了几下,但循环还是没停下来,系统还是没捕获到按钮的动作。
可定时器的扫描速度已经很快了啊?
一直把FOR循环中的延时加到sleep(800),定时器才准确获取了按钮的动作,盯着FOR循环部份的代码,陷入困惑中...
...........
...........
晕死,这段代码什么意思
Send("{RIGHT " & $a-1 & "}")
移动插入点前位置 ?
原先没这段代码的,为了举例,用了GUICtrlCreateEdit这个控件,又为了显示检索字符的直观,所以用send 不断发送移动光标的指令。
这么快的FOR循环中,放这个Send,不是相当于一直按着右方向键不放么,难怪按钮不正常工作,被组合了。
屏掉这段再试,OK,可以。
再测,接着
;GUICtrlSetOnEvent($Button2, "tingzhi")
;GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
把这两个也屏掉,只用定时器临控按钮焦点
顺利,看来Send("{RIGHT " & $a-1 & "}") 是罪魁祸首,俺错怪$WM_COMMAND了。 继续推理下去
既然在定时器里可以监控按钮焦点,那么在FOR循环里也可以加入这个按钮焦点的监控啊
好,再来测一下
把定时器也关了,不要。
呵呵,这应该解决了FOR循环的跳出问题了。
完成代码如下:#include <ButtonConstants.au3>
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#Include <GuiEdit.au3>
Opt("GUIOnEventMode", 1) ; 切换为 OnEvent 模式
Dim $a,$i,$d,$tip
$Form1 = GUICreate("Form1", 820, 620, 100, 50)
GUISetOnEvent($GUI_EVENT_CLOSE, "CLOSEClicked")
$Edit1 = GUICtrlCreateEdit("", 5, 64, 401, 550,$ES_WANTRETURN)
$Edit2 = GUICtrlCreateEdit("", 415, 64, 401, 550,$ES_WANTRETURN)
;BitOR($ES_AUTOVSCROLL,$ES_AUTOHSCROLL,$ES_WANTRETURN))
;-------------------------
$filetext1 = "数据不够自行复制粘贴5B30303039434645435D204C6F6164696E6720446576696365203D2048494D454D2E5359530D0A284C6F676F2064" & _
"697361626C6564290D0A5B30303039434645435D204C6F616453756363657373202020203D2048494D454D2E5359530D0A5B3" & _
"720446576696365203D20474344524F4D2E5359530D0A5B30303039443033375D204C6F61644661696C656420202020203D2047" & _
"0303039434645435D204C6F6164696E6720446576696365203D20514344524F4D2E5359530D0A5B30303039434645445D204C6" & _
"F61645375636365737320202"
$filetext2 = "数据不够自行复制粘贴5B30303039434646465D204C6F6164696E6720446576696365203D20474344524F4D2E5359530D0A5B30303039443" & _
"031335D204C6F61644661696C656420202020203D20474344524F4D2E5359530D0A5B30303039443032335D204C6F6164696E6" & _
"0303039434645435D204C6F6164696E6720446576696365203D20514344524F4D2E5359530D0A5B30303039434645445D204C6" & _
"720446576696365203D20474344524F4D2E5359530D0A5B30303039443033375D204C6F61644661696C656420202020203D2047" & _
"4344524F4D2E5359530D0A"
GUICtrlSetData($Edit1,$filetext1)
GUICtrlSetData($Edit2,$filetext2)
ControlFocus ("Form1","",$Edit1)
Send("^{Home}")
;--------------------------
$Button1 = GUICtrlCreateButton("比较", 5, 16, 75, 25)
$Button2 = GUICtrlCreateButton("停止", 105, 16, 75, 25)
GUICtrlSetOnEvent($Button1, "huoquData1")
;-----------------------------------------------
GUISetState(@SW_SHOW)
While 1
Sleep(1)
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
EndSwitch
WEnd
Func huoquData1()
$x = 0 ;循环启动标识
$tip = 0
ControlFocus ("Form1","",$Edit1)
$GetData1 = GUICtrlRead ($Edit1)
$GetData2 = GUICtrlRead ($Edit2)
$RightDataA = StringLen($GetData1) ;最后一个字符的位置
$a = 0
$d = $RightDataA
For $i =1 To $d Step 1
Sleep(10)
If ControlGetFocus ("Form1") = "Button2" Then
MsgBox(0,"","中止FOR循环!")
Return
EndIf
$a = $a + 1
;-------------移动------
ControlFocus ("Form1","",$Edit1)
If $a-1 = 0 Then Send("^{Home}")
_GUICtrlEdit_InsertText($Edit1,"",$a)
Send("^z")
;-------------移动------
$MidDataA = StringMid ($GetData1,$a,1)
$MidDataB = StringMid ($GetData2,$a,1)
$ComData = StringCompare ($MidDataA,$MidDataB,1) ;比较两个数值
If $ComData <> 0 Then
$tip = $tip + 1
TrayTip("循环中","发现" & $tip &"处不同",10, 1)
EndIf
Next
EndFunc
Func CLOSEClicked()
GUIDelete()
Exit
EndFunc
这么长的代码,叫人家逐行给你检查代码啊,楼主应该精简一下代码再粘出来询问 不如直接把代码掉进whlie里处理
页:
[1]