水木子 发表于 2019-12-29 19:11:21

请教一个关于循环执行任务的问题

本帖最后由 水木子 于 2019-12-29 19:21 编辑

最近在帮朋友写一个小程序,涉及到需要循环挨个执行任务,一直没有什么好的方法,特来请教下大家,还望大家不吝赐教。

我先说明下需求吧!
1、每个循环的循环次数是不定的,不一定都是10次。
2、必须等前面的循环执行完毕,再接着执行后面的循环。比如勾选了 “循环2”和“循环4”,那么就先执行完“循环2”,之后再开始“循环4”
3、可随时相应按钮控制,比如循环开始以后,可以点击“结束”按钮,立即结束循环。

不知道我表达清楚没有,目前我的解决方法如下,但是我始终觉得不够好。还请大家帮忙想想有没有其他更好的方法。
看似一个挺简单的问题,但我思索了许久,一直没有想出比较好的解决方法。
Global $bBoolean = True, $iZ
Global $Checkbox
Global $hGUI = GUICreate('', 300, 400)
$Checkbox = GUICtrlCreateCheckbox('循环1', 60, 50, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环2', 180, 50, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环3', 60, 100, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环4', 180, 100, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')

$Label1 = GUICtrlCreateLabel('', 50, 200, 200, 20, 0x01 + 0x0200)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Label2 = GUICtrlCreateLabel('准备就绪', 50, 250, 200, 20, 0x01 + 0x0200)
GUICtrlSetFont(-1, 14, 400, 0, '微软雅黑')

$Button1 = GUICtrlCreateButton('开始', 50, 300, 80, 30)
$Button2 = GUICtrlCreateButton('结束', 170, 300, 80, 30)
GUISetState()

While 1
      $nMsg = GUIGetMsg()
      Switch $nMsg
                Case -3
                        Exit
                Case $Button1
                        $bBoolean = True
                        If GUICtrlRead($Checkbox) = 1 and $bBoolean = True Then
                              $bBoolean = False
                              $iZ = 0
                              GUICtrlSetData($Label1, '正在执行 循环1')
                              AdlibRegister('MyFunc', 500)

                              Wait()
                        EndIf

                        If GUICtrlRead($Checkbox) = 1 and $bBoolean = TrueThen
                              $bBoolean = False
                              $iZ = 0
                              GUICtrlSetData($Label1, '正在执行 循环2')
                              AdlibRegister('MyFunc', 500)

                              Wait()
                        EndIf

                        If GUICtrlRead($Checkbox) = 1 and $bBoolean = TrueThen
                              $bBoolean = False
                              $iZ = 0
                              GUICtrlSetData($Label1, '正在执行 循环3')
                              AdlibRegister('MyFunc', 500)

                              Wait()
                        EndIf

                        If GUICtrlRead($Checkbox) = 1 and $bBoolean = TrueThen
                              $bBoolean = False
                              $iZ = 0
                              GUICtrlSetData($Label1, '正在执行 循环4')
                              AdlibRegister('MyFunc', 500)

                              Wait()
                        EndIf

                Case $Button2
                        AdlibUnRegister()
                        $bBoolean = False
                        GUICtrlSetData($Label1, '手动结束循环')

      EndSwitch
WEnd

Func Wait()
      While 1
                If $bBoolean = True Then ExitLoop

                $nMsg2 = GUIGetMsg()
                Switch $nMsg2
                        Case -3
                              Exit

                        Case $Button2
                              AdlibUnRegister()
                              $bBoolean = False
                              GUICtrlSetData($Label1, '手动结束循环')
                              ExitLoop
                EndSwitch
      WEnd
EndFunc   ;==>Wait

Func MyFunc()
      $iZ += 1
      GUICtrlSetData($Label2, $iZ)

      If $iZ = 10 Then
                AdlibUnRegister()
                $bBoolean = True
                GUICtrlSetData($Label1, '循环完成')
      EndIf
EndFunc   ;==>MyFunc


afan 发表于 2019-12-29 19:18:13

挺好的 好像木有问题啊~~

水木子 发表于 2019-12-29 19:20:31

afan 发表于 2019-12-29 19:18
挺好的 好像木有问题啊~~

谢谢前辈的支持,请不要受我代码的影响,如果让你来写,这样的问题,你会用什么方法呢?

afan 发表于 2019-12-29 19:48:34

本帖最后由 afan 于 2019-12-29 19:51 编辑

不知道木子的用途,我只能按自己的方式搞一下
Opt('GUIOnEventMode', 1)

Global $hGUI, $Checkbox, $Label1, $Label2, $Button2
_Test()

Func _Test()
      $hGUI = GUICreate('', 300, 400)
      GUISetFont(12, 400, 0, '微软雅黑')
      GUISetOnEvent(-3, '_Close')
      $Checkbox = GUICtrlCreateCheckbox('循环1', 60, 50, 97, 17)
      $Checkbox = GUICtrlCreateCheckbox('循环2', 180, 50, 97, 17)
      $Checkbox = GUICtrlCreateCheckbox('循环3', 60, 100, 97, 17)
      $Checkbox = GUICtrlCreateCheckbox('循环4', 180, 100, 97, 17)
      $Label1 = GUICtrlCreateLabel('', 50, 200, 200, 20, 0x01 + 0x0200)
      $Label2 = GUICtrlCreateLabel('准备就绪', 50, 250, 200, 20, 0x01 + 0x0200)
      GUICtrlCreateButton('开始', 50, 300, 80, 30)
      GUICtrlSetOnEvent(-1, '_Start')
      $Button2 = GUICtrlCreateButton('结束', 170, 300, 80, 30)
      GUISetState()
      While 1
                Sleep(1000)
      WEnd
EndFunc   ;==>_Test

Func _Start()
      Opt('GUIOnEventMode', 0)
      For $ii = 0 To 3
                If GUICtrlRead($Checkbox[$ii]) = 1 Then
                        GUICtrlSetData($Label1, '正在执行 循环' & $ii + 1)
                        For $jj = 1 To 10
                                $ts = TimerInit()
                              Do
                                        Switch GUIGetMsg()
                                                Case -3
                                                      _Close()
                                                Case $Button2
                                                      GUICtrlSetData($Label1, '手动结束循环')
                                                      ExitLoop 3
                                        EndSwitch
                              Until TimerDiff($ts) > 500
                              GUICtrlSetData($Label2, $jj)
                        Next
                        GUICtrlSetData($Label1, '循环完成')
                EndIf
      Next
      Opt('GUIOnEventMode', 1)
EndFunc   ;==>_Start

Func _Close()
      Exit
EndFunc   ;==>_Close

水木子 发表于 2019-12-29 19:57:23

本帖最后由 水木子 于 2019-12-29 19:58 编辑

afan 发表于 2019-12-29 19:48
不知道木子的用途,我只能按自己的方式搞一下
Opt('GUIOnEventMode', 1)


是这样的,这个小程序的主要作用是,定时监测某窗口上是否出现某按钮,如果出现了则按下,$iZ += 1
如此往复 当 $iZ =n则结束循环,继续执行下一个循环。中途可以手动停止监测。就是这么回事。
另外前辈给出的代码,我这边执行出错。Until TimerDiff($ts) $ts未申明。

zghwelcome 发表于 2019-12-29 20:03:30

本帖最后由 zghwelcome 于 2019-12-29 20:05 编辑


#include <WindowsConstants.au3>
Global $bBoolean = True
Global $Checkbox
Global $hGUI = GUICreate('', 300, 400)
$Checkbox = GUICtrlCreateCheckbox('循环1', 60, 50, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环2', 180, 50, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环3', 60, 100, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Checkbox = GUICtrlCreateCheckbox('循环4', 180, 100, 97, 17)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')

$Label1 = GUICtrlCreateLabel('', 50, 200, 200, 20, 0x01 + 0x0200)
GUICtrlSetFont(-1, 12, 400, 0, '微软雅黑')
$Label2 = GUICtrlCreateLabel('准备就绪', 50, 250, 200, 20, 0x01 + 0x0200)
GUICtrlSetFont(-1, 14, 400, 0, '微软雅黑')

$Button1 = GUICtrlCreateButton('开始', 50, 300, 80, 30)
$Button2 = GUICtrlCreateButton('结束', 170, 300, 80, 30)
GUISetState()
GUIRegisterMsg($WM_SYSCOMMAND, "On_WM_SYSCOMMAND")
GUIRegisterMsg($WM_COMMAND, "WM_COMMAND")
While 1
      $nMsg = GUIGetMsg()
      Switch $nMsg
                Case -3
                        Exit
                Case $Button1
                        $bBoolean = True
                        For $i = 0 To UBound($Checkbox) - 1
                              If Not $bBoolean Then ExitLoop
                              If GUICtrlRead($Checkbox[$i]) = 1 Then
                                        Local $vLoopNum = Random(5,10,1)
                                        GUICtrlSetData($Label1, '正在执行 循环' & $i + 1)
                                        _Loop($i + 1 ,$vLoopNum)
                              EndIf
                        Next
                        
      EndSwitch
WEnd


Func _Loop($vLoopIndex , $vLoopNum)
      For $j = 1 To $vLoopNum
                GUICtrlSetData($Label2, '循环' & $vLoopIndex & '    ' & $j & '/' & $vLoopNum)
                For $t = 1 To 2
                        Sleep(250)
                        If Not $bBoolean Then Return GUICtrlSetData($Label1, '手动结束循环')
                Next
      Next
EndFunc   ;==>_Loop


Func WM_COMMAND($hWnd, $iMsg, $iwParam, $ilParam)
      $iCode = BitShift($iwParam, 16)
      Switch $ilParam
                Case GUICtrlGetHandle($Button2)
                        $bBoolean = False                        
      EndSwitch
      Return
EndFunc   ;==>WM_COMMAND

Func On_WM_SYSCOMMAND($hWnd, $nMsg, $wParam, $lParam)
      Local Const $SC_CLOSE = 0xF060
      Switch BitAND($wParam, 0xFFF0)
                Case $SC_CLOSE
                        GUIDelete()
                        Exit
      EndSwitch
      Return 'GUI_RUNDEFMSG'
EndFunc   ;==>On_WM_SYSCOMMAND


最好的方式应该是hook检测窗口的消息

afan 发表于 2019-12-29 20:05:50

水木子 发表于 2019-12-29 19:57
是这样的,这个小程序的主要作用是,定时监测某窗口上是否出现某按钮,如果出现了则按下,$iZ += 1
如此 ...
之前编辑帖子给误删了,后来加上了
高亮的TAB间距太大了,难看

水木子 发表于 2019-12-29 20:07:01

本帖最后由 水木子 于 2019-12-29 20:09 编辑

zghwelcome 发表于 2019-12-29 20:03
最好的方式应该是hook检测窗口的消息
嗯!这个方法我有想过,但是没有成功。故出此下策。
谢谢!前辈的思路,感激不尽。

水木子 发表于 2019-12-29 20:25:34

本帖最后由 水木子 于 2019-12-29 20:30 编辑

afan 发表于 2019-12-29 20:05
之前编辑帖子给误删了,后来加上了
高亮的TAB间距太大了,难看
前辈这个方法我之前有想过,但是我一直以为循环中有 Sleep 会影响 GUIRegisterMsg 的相应速度,所以就没有继续往下深入,经测试是可行的,看来我要对 GUIRegisterMsg 重新审视了,谢谢!

另外不得不佩服前辈写代码的速度,可以说已经达到了信手拈来的地步,我的帖子刚开,前辈立即跟上。思路与代码也随之跟上,可见神速!佩服,佩服!


afan 发表于 2019-12-29 21:57:46

水木子 发表于 2019-12-29 20:25
前辈这个方法我之前有想过,但是我一直以为循环中有 Sleep 会影响 GUIRegisterMsg 的相应速度,所以就没 ...

木子过奖了哦这不也是在你的代码和思路上改的吗各有千秋罢了~
zghwelcome 的方法也不错,只是个人偏好尽量独立函数化处理完成,尽量少与系统消息挂钩,系统消息我一般只处理主脚本的事件。当然这里只是个小脚本用不着想太多,习惯使然~

xyx115 发表于 2020-1-13 16:47:35

水木子 发表于 2019-12-29 19:57
是这样的,这个小程序的主要作用是,定时监测某窗口上是否出现某按钮,如果出现了则按下,$iZ += 1
如此 ...

我也写过这样一个守护程序,其中循环时的退出,用的热键。

其他的就是循环,在循环中设置几个全局数组,当做触发时机。

页: [1]
查看完整版本: 请教一个关于循环执行任务的问题