【问题标题】:How to await function completion with a loop inside如何使用内部循环等待函数完成
【发布时间】:2017-09-17 07:17:35
【问题描述】:

在下面包含的脚本中,我尝试运行一系列命令。但是当按 F1 运行时,该命令将立即运行两个 SendAndLoopFor() 调用,而无需等待内部循环完成。

我试图通过在函数中添加一个 return "" 来“强制”这个等待,并用它分配一个变量而不是 Foo := SendAndLoopFor(),但即使那样它也不会等待操作。

有没有办法在执行下一个命令之前等待SendAndLoopFor() 命令完成?

#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%  
#MaxThreadsPerHotkey 13
#SingleInstance
F1::
Done = 0
Toggle := !Toggle
Loop
{
    If (!Toggle)
        Break
    SendAndLoopFor("4", -13600)
    SendAndLoopFor("5", -13600)
}
return

SendAndLoopFor(TSend="", Timeout=0)
{
    Send %TSend%
    SetTimer, LoopLimit, %Timeout%
    Loop
    {
        If(!Toggle)
            Break
        If(done == 1)
        {
            done = 0
            Break
        }
        MouseClick, left
        sleep 83
    }
}
LoopLimit:
    Done = 1
Return

【问题讨论】:

  • 您需要在 SendAndLoopF​​or() 之前返回。你指的是一个名为 LoopLimit 的不存在的标签
  • 啊,我确实忘了包括那篇文章。稍后会编辑它
  • AutoHotkey 确实按顺序运行它们,但您的 SendAndLoopFor 循环的 Sleep 时间只有 83 毫秒。这是故意的吗?因为您目前的延迟几乎是难以察觉的。
  • @DavidMetcalfe 但循环将继续,直到中断或超时持续时间。示例中为 13.6 秒。这就是 settimer 部分的用途

标签: autohotkey


【解决方案1】:

您的问题似乎源于对 SetTimer 的误解。它是并行化任务的绝佳工具,因为脚本本身不会在继续执行脚本之前等待计时器。

为了说明这一点,简化脚本,您可以观察到相同的效果。

F3::
SetTimer, LoopLimit, -2000
SendInput, This is stuff happening before the timer.{Enter}
return

LoopLimit:
SendInput, This is stuff happening after.

一个简单的解决方案是计算迭代次数并在达到计数器限制后终止循环。

F3::
count = 0

Loop
{
; Do stuff.

count += 1
Sleep, 1000

if (count >= 5)
{
break
}}

您也可以使用various built-in variables 来比较从循环开始到您的截止值的时间,但是使用这些可能会很痛苦,因此我建议您避免使用它们,除非您的脚本在时间敏感的约束下工作.

根据 cmets 进行编辑:

F1::
Done = 0
Toggle := !Toggle
Loop
{
    If (!Toggle)
        Break
    SendAndLoopFor("4", -13600)
    SendAndLoopFor("5", -13600)
    Sleep, 2000
}
return

SendAndLoopFor(TSend="", Timeout=0)
{
    Send %TSend%
    SetTimer, LoopLimit, %Timeout%
    Loop
    {
        If(!Toggle)
        {
            SendInput, This is inside the Toggle.{Enter}
            Break
        }
        If(done == 1)
        {
            SendInput, This is inside the Done.{Enter}
            done = 0
            Break
        }
        SendInput, This is after the If statements.{Enter}
        MouseClick, left
        Sleep, 999999 ; Note how this has no effect due to above break.
    }
}
LoopLimit:
    Done = 1

【讨论】:

  • 这不是我遇到问题的循环部分。它是函数调用链。 SendAndLoopFor("4", -13600) 内部循环它的“点击”命令。但同时另一个SendAndLoopFor("5", -13600) 也被调用。无需等待第一次调用完成。
  • @MXD 我不认为您有机会测试循环中的每个条件语句?您在SendAndLoopFor 中的If(!Toggle) 始终为真,因此循环总是中断。因为您没有延迟大到足以被察觉的睡眠命令,所以它们似乎同时触发,但事实并非如此。他们就这么快就完成了。我将通过修改您的代码来编辑我的答案以展示这一点。
  • 实际上我以相同的方式在另一个脚本中使用了 If(!Toggle)。它在哪里工作,很好。 gist.github.com/anonymous/36e75336eec880016bc6aef81861edcf(完整脚本)我上面的代码示例使用了完全相同的代码,但将复制粘贴的代码提取到函数中,使代码更枯燥。此外,如果 ' Toggle 语句始终为真,它就不会开始运行。考虑到它也在第一个循环中,即调用命令的那个。
  • @MXD 试试这个脚本,自己看看。您不会比第一个 If 语句更进一步。
  • 我做到了,我的问题不在于设置计时器。但是变量Toggle 是作用域的,因此在被调用函数中不存在。通过在SendAndLoopFor() 中定义变量,我也让它工作了。
猜你喜欢
  • 2020-11-10
  • 1970-01-01
  • 2021-04-23
  • 2019-04-15
  • 1970-01-01
  • 2012-09-30
  • 2020-08-02
  • 2015-06-24
  • 1970-01-01
相关资源
最近更新 更多