2010-07-05 91 views
3

我正在使用WxHaskell以圖形方式顯示使用TCP(我使用Data.Binary解碼)通告狀態更新的程序的狀態。收到更新時,我想更新顯示。所以我希望GUI以異步方式更新它的顯示。我知道processExecAsync異步運行命令行進程,但我不認爲這是我想要的。wxhaskell異步更新

+0

你能否澄清你的問題。你究竟在尋找什麼?從單獨的進程通知Haskell進程的模型? – 2010-07-05 01:09:11

+0

這裏是一個例子。在一個單獨的過程中,有一個計數器。每次計數器遞增時,它都會通過TCP向其他Haskell進程(客戶端)發送消息。客戶端管理一個顯示計數器值的gui(在WxHaskell中)。當客戶端收到更新時,我想更新顯示器上的計數器。 – Alex 2010-07-05 08:42:37

+0

根據你的評論我發佈了一個答案。如果有的話,我的回答中有哪些概念與你的問題有關? Haskell線程(forkIO)?線程之間的通信(MVars,STM/TVars)?別的東西或不在我的答案? – 2010-07-05 18:45:46

回答

2

這是使用事務變量(即軟件事務內存)的粗略代碼。你可以使用IORef,MVar或其他許多構造。

main = do 
    recvFunc <- initNetwork 
    cntTV <- newTVarIO 0 
    forkIO $ threadA recvFunc cntTV 
    runGUI cntTV 0 

上方啓動該程序,初始化網絡和共享變量cntTV

threadA recvCntFromNetwork cntTVar = forever $ do 
    cnt <- recvCntFromNetwork 
    atomically (writeTVar cntTVar cnt) 

threadA從網絡接收數據和寫入計數器的共享變量的新值。

runGUI cntTVar currentCnt = do 
    counter <- initGUI 
    cnt <- atomically $ do 
     cnt <- readTVar cntTVar 
     if (cnt == currentCnt) 
      then retry 
      else return cnt 
    updateGUICounter counter cnt 
    runGUI cntTVar cnt 

runGUI讀取共享變量,如果有變化將更新GUI計數器。僅供參考,runGUI線程不會在retry上被喚醒,直到cntTVar被修改,所以這不是一個CPU佔用輪詢循環。

在這段代碼中,我假設你有函數updateGUICounter,initGUIinitNetwork。我建議你使用Hoogle來查找你還不知道的其他功能的位置,並學習一些關於每個模塊的知識。

+0

感謝您的回答。這是我想到的。不幸的是,我們需要調用啓動事件循環的wxHaskell函數'start'。如果我們運行'start runGUI',那麼事件循環將永遠不會啓動。如果我們'forkIO'STM的東西,那麼GUI不會更新(至少在我嘗試時)。 – Alex 2010-07-05 20:48:27

1

我想出了一種似乎可行的hack。也就是說,使用事件計時器來檢查更新隊列:

startClient :: IO (TVar [Update]) 
startClient = /*Connect to server, 
       listen for updates and add to queue*/ 

gui :: TVar [Update] -> IO() 
gui trdl = do 
    f <- frame [text := "counter", visible := False] 
    p <- panel f [] 
    st <- staticText p [] 
    t <- timer f [interval := 10, on command := updateGui st] 
    set f [layout := container p $ fill $ widget st, clientSize := (sz 200 100), visible := True] 
where 
    updateGui st = do 
      rdl <- atomically $ readTVar trdl 
      atomically $ writeTVar trdl [] 
      case rdl of 
       [] -> return() 
       dat : dl -> set st [text := (show dat)] 

main :: IO() 
main = startClient >>= start gui 

因此,客戶端偵聽TCP連接上的更新,將它們添加到隊列中。每隔10ms,就會發起一個事件,其操作是檢查此隊列並在靜態文本小部件中顯示最新更新。

如果您有更好的解決方案,請告訴我!

+0

從我可以告訴沒有任何理由貴公司不能在TVAR重試,並做這種異步(但是,是的,任何時候線程阻塞wx似乎中斷)。我也嘗試了反轉這個概念,並且將'st str [text:= str]'寫入TVar,然後讓'startClient'調用這個來更新GUI,但是這似乎無限地阻塞了'set'。 WX已經證明相當令人沮喪,所以我認爲我會堅持使用GTK。 – 2010-07-06 18:53:08

0

我發現在沒有忙等待一個解決方案: http://snipplr.com/view/17538/

然而,你可能會爲了避免與現有的ID衝突選擇更高的事件ID。

這裏是我的模塊http://code.haskell.org/alsa/gui/src/Common.hs一些代碼:

myEventId :: Int 
myEventId = WXCore.wxID_HIGHEST+100 
    -- the custom event ID, avoid clash with Graphics.UI.WXCore.Types.varTopId 

-- | the custom event is registered as a menu event 
createMyEvent :: IO (WXCore.CommandEvent()) 
createMyEvent = 
    WXCore.commandEventCreate WXCore.wxEVT_COMMAND_MENU_SELECTED myEventId 

registerMyEvent :: WXCore.EvtHandler a -> IO() -> IO() 
registerMyEvent win io = 
    WXCore.evtHandlerOnMenuCommand win myEventId io 


reactOnEvent, reactOnEventTimer :: 
    SndSeq.AllowInput mode => 
    Int -> WX.Window a -> Sequencer mode -> 
    (Event.T -> IO()) -> 
    IO() 
reactOnEvent _interval frame (Sequencer h _) action = do 
    mvar <- MVar.newEmptyMVar 

    void $ forkIO $ forever $ do 
     MVar.putMVar mvar =<< Event.input h 
     WXCore.evtHandlerAddPendingEvent frame =<< createMyEvent 

    registerMyEvent frame $ 
     MVar.takeMVar mvar >>= action 

-- naive implementation using a timer, requires Non-Blocking sequencer mode 
reactOnEventTimer interval frame sequ action = 
    void $ 
    WX.timer frame [ 
     WX.interval := interval, 
     on command := getWaitingEvents sequ >>= mapM_ action] 

的代碼顯示了兩種方式來處理這個問題:

  • reactOnEventTimer不使用WX定時器忙等待。
  • reactOnEvent只有在事件實際到達時纔會激活。這是首選解決方案。

在我的例子中,我等待ALSA MIDI音序器消息。 Event.input調用等待下一個ALSA消息。 action獲取Event.input的結果,即傳入的ALSA消息,但它在WX線程中運行。

+1

歡迎來到StackOverflow。雖然這可能回答 問題,[這將是更可取的](http://meta.stackexchange.com/questions/8231/are-answers-that-just-contain-links-elsewhere-really-good-answers/8259 #8259)在這裏包括答案的基本部分,並提供供參考的鏈接。 – Chris 2012-09-26 07:33:06