wxLua - Как мне реализовать кнопку Отмена?

У меня есть приложение wxLua Gui с кнопкой "Выполнить". В зависимости от выбранных параметров, запуск может занять много времени, поэтому я хотел бы реализовать кнопку / функцию "Отмена". Но похоже, что все в wxLua работает в одном потоке Gui, и как только вы нажмете "Выполнить", нажатие кнопки "Отмена" ничего не сделает, запуск всегда будет завершен.

Отмена в основном устанавливает переменную в true, и запущенный процесс регулярно проверяет эту переменную. Но событие нажатия кнопки Отмена никогда не происходит во время работы.

Я никогда не использовал сопрограммы; если процесс "Выполнить" регулярно уступает процессу "Отмена проверки", произойдет ли событие "Отмена"?

Или есть другой способ?

2 ответа

Решение

(ниже предполагается, что под "Выполнить" вы подразумеваете длительную операцию в одном и том же процессе, а не запуск внешнего процесса с использованием wxExecute или wxProcess.)

Событие "Отмена" не вызывается, потому что, выполняя логику "Выполнить", пользователь не получает возможность обрабатывать событие нажатия.

Чтобы избежать блокировки пользовательского интерфейса, вы должны сделать что-то вроде этого. Когда вы нажмете кнопку "Выполнить", создайте подпрограмму вокруг функции, которую хотите запустить:

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() в нужное время (не слишком короткое, поскольку вы будете тратить время на переключение назад и вперед и не слишком продолжительное, чтобы пользователи замечали задержки в пользовательском интерфейсе); Вы, вероятно, должны поэкспериментировать с этим, но может работать что-то на основе таймера с интервалом примерно 100 мс.

Вы можете проверить значения Отмена либо в своем обработчике события IDLE, либо в долговременной функции, как вы это делаете сейчас. Логика, которую я описал, даст вашему интерфейсу приложения возможность обрабатывать событие отмены так, как вы ожидаете.

Я не использую WXWidgets, но способ, которым я реализую кнопки отмены в моих сценариях lua, которые используют IUP, заключается в том, чтобы иметь флаг отмены, который устанавливается при нажатии кнопки и проверке отображения хода выполнения во время выполнения.

Использование это так

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

Другие вопросы по тегам