关于创建进度条的问题大家好。 我创建了一个带有进度条和“取消”按钮的窗口。 目的是允许用户停止程序执行。 当我按取消时,我收到错误,并且不知道如何解决它。 我的脚本的简化版本如下。
Names Default to Here(1);
//Define progress window
pwin = NewWindow("Progress",
SB_L = SpacerBox(Size(0, 15), Color("Green")),
ButtonBox("Cancel",
pwin << Close Window;
Stop();
)
);
//Sample Loop
For(i=1, i<=10, i++,
SB_L << Size(i*10, 15); //update the progress bar
Wait(1); //rest of loop
);如果我在循环运行时按“取消”,则会收到以下错误:
deleted object reference: SB_L << Size(i * 10, 15) in access or evaluation of 'Glue' , pwin = New Window("Progress",
SB_L = Spacer Box(Size(0, 15), Color("Green")),
Button Box("Cancel",
pwin << Close Window;
Stop();
)
); /*###*/For(i = 1, i <= 10, i++,
SB_L << Size(i * 10, 15);
Wait(1);
) /*###*/;当按下取消按钮时,我的期望是进度窗口应该关闭,然后执行应该停止。 但它似乎会继续至少一次迭代,并在 For 循环中的 SB_L << Size() 行处失败。 它失败了,因为进度窗口已关闭并且 SB_L 已被删除,但我很困惑为什么如果发出 Stop() 命令则执行此行?
即使在我的 Stop() 命令之后程序执行仍在继续,我是否正确? 按下“取消”按钮后,如何防止执行 SB_L << Size() 命令?
细节:
JMP 专业版 15.2.1
Mac 操作系统 Big Sur v11.6
谢谢。
高级统计建模自动化和脚本编写数据混合和清理大规模定制质量和工艺工程回复:关于创建进度条的问题不幸的是,如果不做本质上是不良做法的黑客行为,你就无法在这里做你想做的事。JMP 脚本是单线程的,带有取消按钮的进度条大多只在多线程系统中有意义,在该系统中,主线程上有 GUI/事件循环,而工作线程上有所有脚本和函数调用。
即使在这些情况下,您也需要某种哨兵来正确处理取消等问题。当然可以使用取消按钮杀死线程,但一般来说,您需要一个安全的停止路径——某种中止分支。
您可以在 JSL 中执行此操作,但它需要等待( ... )陈述或<<更新窗口()声明,两者都可能产生严重后果。值得注意的是,您可能会在事件循环期间无意执行代码,这些代码可能会破坏脚本中的变量名称 - 例如,如果图形脚本存在于图形上并被执行(JMP 非常积极地执行图形脚本),则可能会发生这种情况,并且这些脚本可能来自您无法控制的其他插件存在于用户系统上。当然,最好在脚本完成之前永远不要将执行返回给事件循环(显然要使脚本尽可能短,以避免 JMP 出现冻结)。简而言之,不要将执行交还给事件循环。
我个人认为 JMP 团队目前在 JSL 中没有多线程执行范例(快到 2022 年了!)有点短视,但事实就是如此。
需要注意的一件事是——您可以运行外部程序并通过 IPC 通过 STDOUT 与它们对话。例如,您可以使用 Python 执行某种长时间运行的工作,并使用 STDOUT 来了解其何时完成(甚至可以在某种 STDOUT 哨兵上启动 JMP 脚本)。
回复:关于创建进度条的问题是的。 按钮脚本在其自己的“上下文”中运行;它不知道还有另一个脚本正在运行等待语句。 他们可以通过全局变量进行通信。 为了完成奇怪的可能性,在按钮脚本中使用等待还意味着您可以单击运行脚本的窗口上的关闭 X...当等待完成时, jmp 尝试安全地停止脚本。 通常,如果在等待期间关闭了保存按钮脚本的窗口,则等待后的下一条语句将不会被执行。
编辑:此外,需要等待来处理取消按钮的点击。
回复:关于创建进度条的问题嗨克雷格! 谢谢。 只是为了澄清,我添加的“等待(1)”只是为了模仿此演示的一组较长命令的执行,并给自己足够的时间来单击“取消”,以便我可以重现问题。 但并不打算让等待成为脚本的必要部分。
如果我可以尝试总结一下我相信你所说的话:
“取消”按钮调用独立于脚本 A(包含 For 循环的主脚本)的脚本 B。 脚本 B 中的 Stop 命令可以停止脚本 B 的执行,但不能/不会影响脚本 A。
我的说法正确吗,更多/更少?
回复:关于创建进度条的问题wait( n ) 是 JMP 中不可避免的祸害,应尽可能避免。 在等待期间,调用 wait 的脚本会暂停,而操作系统可以执行一些操作,例如识别单击或使打开的窗口可见。 奇怪的事情可能会发生,因为您可以使用单击来启动另一个接触第一个脚本环境的脚本(您的示例)。 在您的示例中,stop() 正在停止第二个脚本。 它还可以设置全局标志。 如果您的项目足够大,需要担心跟踪全局变量,您也可以使用名称空间。
那么可能发生什么奇怪的事情呢? 大多数窗口被关闭,或者显示框被删除。 特别是,想象一下单击函数有一个使用 wait(1) 的脚本,半秒后您再次单击该按钮。 该脚本的第二个副本正在第一个副本内运行。 原始的 wait(1) 在第二个脚本完成之前不会返回。 如果第二个脚本关闭按钮所在的窗口,那么原始脚本周围的环境是什么? (与等待之前不同!)不要构建没有充分理由需要等待的脚本;大多数时候,displaybox<<回复:关于创建进度条的问题
刚刚注意到其他有趣的事情。 如果我在“取消”按钮脚本中注释掉“pwin << Close Window()”命令,则取消按钮不再停止执行。 当从按钮执行 Stop() 命令时,它似乎无法停止 For 循环。 取消按钮之前之所以能够停止执行,只是因为删除窗口会产生错误。
回复:关于创建进度条的问题谢谢瑞安(和克雷奇)。 这是我肯定会考虑的一个选项,但它需要向主脚本正文中的 if 子句发送一个标志。 我的愿望是使用“取消”按钮中的 Stop() 命令停止程序执行。 也许我可以重新构造我的问题:为什么我的 Stop() 命令似乎没有停止执行?
回复:关于创建进度条的问题你好@尼克尔斯。 您可能想查看最近的这篇文章@Craige_Hales ,带有取消按钮的进度条。