2012-09-13 85 views
2

我有一個wxLua Gui應用程序,它有一個「運行」按鈕。根據選擇的選項,Run可能需要很長時間,所以我想實現「取消」按鈕/功能。但它看起來像wxLua中的所有內容都在一個Gui線程中工作,並且一旦你點擊Run,按下Cancel就什麼也不做,Run總是完成。wxLua - 如何實現取消按鈕?

取消基本上將變量設置爲true,並且運行過程會定期檢查該變量。但是,運行時絕不會發生取消按鈕按下事件。

我從來沒有用過co-routines;如果運行進程定期產生「取消檢查」進程,那麼取消事件會發生嗎?

或者還有另外一種方法嗎?

回答

3

(以下假定由「運行」你的意思是一個長期運行在相同的過程中運行,並且而不是使用wxExecute或wxProcess運行外部進程。)

「取消」事件不會被觸發,因爲通過執行您的運行邏輯,您沒有給UI處理單擊事件的機會。

爲了避免阻塞UI,你需要做這樣的事情。當你點擊運行按鈕周圍的函數創建一個協程要運行:

coro = coroutine.create(myLongRunningFunction) 

你運行的事件在此時完成。然後,在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事件,除非有一些其他的事件觸發。假設您的處理程序具有event參數,則可以執行event:RequestMore(true)以請求更多的IDLE事件(RequestMore)。

您的長時間運行的過程需要在正確的時間調用coroutine.yield()(不要太短,因爲您將浪費時間來回切換,而且用戶不會注意UI延遲) ;你可能需要試驗這個,但是基於計時器的調用可能需要100ms左右。

您可以像現在一樣在IDLE事件處理程序或長時間運行的函數中檢查取消值。我所描述的邏輯將爲您的應用程序用戶界面提供按照您的預期處理Cancel事件的機會。

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