首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >wxhaskell异步更新

wxhaskell异步更新
EN

Stack Overflow用户
提问于 2010-07-05 08:24:46
回答 3查看 451关注 0票数 3

我使用WxHaskell以图形方式显示一个程序的状态,该程序使用TCP (我使用Data.Binary解码)通告状态更新。当收到更新时,我想要更新显示。所以我希望GUI异步更新它的显示。我知道processExecAsync异步运行命令行进程,但我不认为这是我想要的。

EN

回答 3

Stack Overflow用户

发布于 2010-07-06 02:32:24

这是使用事务变量(即软件事务内存)的粗略代码。您可以使用IORef、MVar或许多其他构造。

代码语言:javascript
复制
main = do
    recvFunc <- initNetwork
    cntTV <- newTVarIO 0
    forkIO $ threadA recvFunc cntTV
    runGUI cntTV 0

在上面启动程序,初始化网络和一个共享变量cntTV

代码语言:javascript
复制
threadA recvCntFromNetwork cntTVar = forever $ do
    cnt <- recvCntFromNetwork
    atomically (writeTVar cntTVar cnt)

threadA从网络接收数据,并将计数器的新值写入共享变量。

代码语言:javascript
复制
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读取共享变量,如果有更改,将更新图形用户界面计数器。仅供参考,CPU线程不会在retry上唤醒,直到cntTVar被修改,所以这不是一个runGUI独占轮询循环。

在这段代码中,我假设您有名为updateGUICounterinitGUIinitNetwork的函数。我建议您使用Hoogle查找您不知道的任何其他函数的位置,并了解一些关于每个模块的信息。

票数 2
EN

Stack Overflow用户

发布于 2010-07-06 07:03:08

我想出了一种似乎有效的黑客方法。即,使用事件定时器检查更新队列:

代码语言:javascript
复制
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,就会引发一个事件,该事件的操作是检查此队列并在静态文本小部件中显示最新更新。

如果你有更好的解决方案,请让我知道!

票数 1
EN

Stack Overflow用户

发布于 2012-09-26 15:22:46

我在http://snipplr.com/view/17538/上找到了一个没有忙碌等待的解决方案

但是,您可以选择更高的eventId,以避免与现有ids冲突。

下面是我的模块http://code.haskell.org/alsa/gui/src/Common.hs中的一些代码

代码语言:javascript
复制
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 timer.
  • reactOnEvent执行忙碌等待,只有当事件实际到达时才会激活。这是首选的解决方案。

在我的示例中,我等待ALSA MIDI sequencer消息。Event.input调用等待下一条ALSA消息到来。action获取Event.input的结果,也就是传入的ALSA消息,但它在WX线程中运行。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3176682

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档