我正在使用WxHaskell以图形方式显示使用TCP(我使用Data.Binary解码)通告状态更新的程序的状态。收到更新时,我想更新显示。所以我希望GUI以异步方式更新它的显示。我知道processExecAsync
异步运行命令行进程,但我不认为这是我想要的。wxhaskell异步更新
回答
这是使用事务变量(即软件事务内存)的粗略代码。你可以使用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
,initGUI
和initNetwork
。我建议你使用Hoogle来查找你还不知道的其他功能的位置,并学习一些关于每个模块的知识。
感谢您的回答。这是我想到的。不幸的是,我们需要调用启动事件循环的wxHaskell函数'start'。如果我们运行'start runGUI',那么事件循环将永远不会启动。如果我们'forkIO'STM的东西,那么GUI不会更新(至少在我尝试时)。 – Alex 2010-07-05 20:48:27
我想出了一种似乎可行的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,就会发起一个事件,其操作是检查此队列并在静态文本小部件中显示最新更新。
如果您有更好的解决方案,请告诉我!
从我可以告诉没有任何理由贵公司不能在TVAR重试,并做这种异步(但是,是的,任何时候线程阻塞wx似乎中断)。我也尝试了反转这个概念,并且将'st str [text:= str]'写入TVar,然后让'startClient'调用这个来更新GUI,但是这似乎无限地阻塞了'set'。 WX已经证明相当令人沮丧,所以我认为我会坚持使用GTK。 – 2010-07-06 18:53:08
我发现在没有忙等待一个解决方案: 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线程中运行。
欢迎来到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
- 1. 异步更新
- 2. 异步TaskUI更新
- 3. 更新UI异步?
- 4. 异步插入&更新异步插入&更新:NoSql和SQL
- 5. 更新DIV异步---更新评论
- 6. 异步更新数据库
- 7. ASP.NET异步标签更新
- 8. Peewee异步更新时
- 9. 异步更新vaadin组件
- 10. 更新ASP.NET面板异步
- 11. 用异步更新图像
- 12. 异步更新WPF窗口
- 13. RestSharp异步API - 更新GUI
- 14. 异步更新控制
- 15. ListView SimpleCursorAdapter异步更新
- 16. 异步任务更新UI
- 17. ASIHTTPRequest异步更新uitableview
- 18. Spark用于异步更新。
- 19. 异步更新文本框
- 20. 异步更新ASP.NET图表
- 21. 如何异步更新winform?
- 22. 异步进度栏更新
- 23. 异步更新面板_
- 24. UICollectionView异步更新大小
- 25. ListActivity的异步更新
- 26. 异步使用异步和等待更新Winforms中一个TreeView
- 27. 异步更新wpf UI从另一个线程异步
- 28. Xamarin.Forms ListView ItemsSource - 异步更新NullReferenceException
- 29. 自动完成UITextField异步更新UITableView
- 30. 使用WakefulIntentService管理异步GPS更新
你能否澄清你的问题。你究竟在寻找什么?从单独的进程通知Haskell进程的模型? – 2010-07-05 01:09:11
这里是一个例子。在一个单独的过程中,有一个计数器。每次计数器递增时,它都会通过TCP向其他Haskell进程(客户端)发送消息。客户端管理一个显示计数器值的gui(在WxHaskell中)。当客户端收到更新时,我想更新显示器上的计数器。 – Alex 2010-07-05 08:42:37
根据你的评论我发布了一个答案。如果有的话,我的回答中有哪些概念与你的问题有关? Haskell线程(forkIO)?线程之间的通信(MVars,STM/TVars)?别的东西或不在我的答案? – 2010-07-05 18:45:46