2

我有一个带有“运行”按钮的 wxLua Gui 应用程序。根据选择的选项,运行可能需要很长时间,所以我想实现一个“取消”按钮/功能。但看起来 wxLua 中的所有东西都在一个 Gui 线程上运行,一旦你点击 Run,按 Cancel 什么都不会,Run 总是会完成。

Cancel 基本上将一个变量设置为 true,并且正在运行的进程会定期检查该变量。但是运行时不会发生取消按钮按下事件。

我从未使用过协同程序;如果 Run 过程定期产生“取消检查”过程,那么 Cancel 事件会发生吗?

还是有其他方法?

4

2 回答 2

3

(以下假设“运行”是指在同一进程中长时间运行的操作,而不是使用 wxExecute 或 wxProcess 运行外部进程。)

“取消”事件不会被触发,因为通过执行您的运行逻辑,您还没有给 UI 处理点击事件的机会。

为避免阻塞 UI,您需要执行以下操作。当您单击“运行”按钮时,围绕要运行的函数创建一个协程:

coro = coroutine.create(myLongRunningFunction)

您的 Run 事件此时已完成。然后在 EVT_IDLE 事件中,只要它不完整,你就会恢复这个协程。它看起来像这样:

if coro then -- only if there is a coroutine to work on
  local ok, res = coroutine.resume(coro, additional, parameters)
  -- your function either yielded or returned
  -- you may check ok to see if there was an error
  -- res can tell you how far you are in the process
  -- coro can return multiple values (just give them as parameters to yield)
  if coroutine.status(coro) == 'dead' then -- finished or stopped with error
    coro = nil
    -- do whatever you need to do knowing the process is completed
  end
end

只要您的进程未完成,您可能需要请求更多 IDLE 事件,因为某些操作系统不会触发 IDLE 事件,除非触发了其他一些事件。假设您的处理程序有event参数,您可以event:RequestMore(true)请求更多 IDLE 事件(RequestMore)。

您的长时间运行的流程需要在正确的时间调用 coroutine.yield() (不要太短,因为您会浪费时间来回切换,也不要太长时间让用户注意到 UI 中的延迟);您可能需要对此进行试验,但是基于计时器的调用之间有 100 毫秒左右的时间可能会起作用。

您可以像现在一样在 IDLE 事件处理程序或长时间运行的函数中检查 Cancel 值。我描述的逻辑将使您的应用程序 UI 有机会按您的预期处理 Cancel 事件。

于 2012-09-13T18:39:28.013 回答
1

我不使用 WXWidgets,但我在使用 IUP 的 lua 脚本中实现取消按钮的方式是设置一个取消标志,该标志在按下按钮时设置,并在运行期间检查进度显示。

用法是这样的

ProgressDisplay.Start('This is my progress box',100)
for i=1,100 do
    ProgressDisplay.SetMessage(i.." %")
    fhSleep(50,40)  -- Emulate performing the task 
    ProgressDisplay.Step(1)
    if ProgressDisplay.Cancel() then
        break
    end
end 
ProgressDisplay.Reset()
ProgressDisplay.Close() 

如果您想查看 ProgressDisplay 的定义,请参阅:

http://www.fhug.org.uk/wiki/doku.php?id=plugins:code_snippets:progress_bar

于 2012-09-13T18:27:08.133 回答