找回密码
 加入
搜索
查看: 4473|回复: 5

[AU3基础] [已解决]跳出FOR循环难题

[复制链接]
发表于 2011-10-20 12:09:55 | 显示全部楼层 |阅读模式
本帖最后由 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 = 0  Then
                                                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        
 楼主| 发表于 2011-10-21 08:01:59 | 显示全部楼层
呵呵,自问自答一下吧。
热键通过键盘发送指令,按钮通过鼠标发送指令。
按钮事件与键盘事件的一个不同之处就是:系统要多一个判断按钮状态的持续性的步骤。
如果由于某种原因,干扰了系统获取按钮的状态,那么即使设置了截取按钮消息也应该是无用了,嗯,有门。
这是因为FOR循环对资源的占用吗?
按钮状态未按与已按,不就是获得了键盘焦点吗?
突然想起帮助文档里似乎有一个判断控件焦点状态的函数,赶紧翻一下看。
果然,
ControlGetFocus   返回指定窗口上键盘焦点所在的控件的类别名.
汗,这个函数居然忘了。
把这个函数放到定时器里,分分钟监控按钮的动作,应该可以的。

改动定时器内的代码:
Func Timer($hWnd, $uiMsg, $idEvent, $dwTime)           
       If ControlGetFocus ("Form1") = "Button2" Then   ;返回指定窗口上键盘焦点所在的控件的类别名.  
                     $x = 1
           EndIf
                        
                                If $tm = 0  Then
                                                If $x = 1 Then           
                                                        $tm = 1            ;不进行二次操作
                                                        ;MsgBox(0,"","测试",1)
                                                        timeclose()       ;关闭定时器
                                                        EndIf
                        Else
                EndIf  
EndFunc
 楼主| 发表于 2011-10-21 08:23:58 | 显示全部楼层
测试后,还是不行啊,按钮的一瞬间,光标闪了几下,但循环还是没停下来,系统还是没捕获到按钮的动作。
可定时器的扫描速度已经很快了啊?
一直把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了。
 楼主| 发表于 2011-10-21 08:45:24 | 显示全部楼层
继续推理下去
既然在定时器里可以监控按钮焦点,那么在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
发表于 2011-10-21 09:42:13 | 显示全部楼层
这么长的代码,叫人家逐行给你检查代码啊,楼主应该精简一下代码再粘出来询问
发表于 2011-10-21 10:05:54 | 显示全部楼层
不如直接把代码掉进whlie里处理
您需要登录后才可以回帖 登录 | 加入

本版积分规则

QQ|手机版|小黑屋|AUTOIT CN ( 鲁ICP备19019924号-1 )谷歌 百度

GMT+8, 2024-5-5 19:32 , Processed in 0.074263 second(s), 21 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表