我正在用反应香蕉和 gtk2hs 编写一些需要从文件句柄中读取的代码。我需要至少有两个线程(一个用反应香蕉读取键盘事件,一个从文件句柄读取),所以目前我的代码看起来像这样:
type EventSource a = (AddHandler a, a -> IO ())
fire :: EventSource a -> a -> IO ()
fire = snd
watch :: EventSource ByteString -> Handle -> IO ()
watch textIn pty = forever $
hGetLine pty >>= fire textIn >> threadWaitRead pty
具有以下主要功能:
mainAxn :: IO ()
mainAxn = do
h <- openFile "foo" ReadMode
initGUI
win <- windowNew
txt <- textViewNew
containerAdd win txt
widgetShowAll win
(keyPress, textIn) <-
(,) <$> newAddHandler <*> newAddHandler
network <- setupNetwork keyPress textIn
actuate network
_ <- forkIO $ watch textIn h
_ <- win `on` keyPressEvent $
eventKeyVal >>= liftIO . fire keyPress >> return True
mainGUI
我的活动网络设置如下:
setupNetwork :: EventSource KeyVal -> EventSource ByteString -> IO EventNetwork
setupNetwork keyPress textIn = compile $ do
ePressed <- fromAddHandler $ addHandler keyPress
eText <- fromAddHandler $ addHandler textIn
reactimate $ print <$> (filterJust $ keyToChar <$> ePressed)
reactimate $ print <$> eText
(除了在我的实际代码中,这些reactimate
调用写入TextView
内置mainAxn
)。我发现我需要构建-threaded
以使事件网络正确捕获来自的文本和来自的textIn
按键keyPress
,这会导致问题,因为同时修改 gtk 包中的对象是不安全的。
目前,postGUIAsync
我的代码中分散了调用,我发现 usingpostGUISync
会导致整个事情陷入僵局——我不知道为什么。我认为这是因为我最终postGUISync
在运行的同一个线程内部调用mainGUI
。
似乎最好在自己的线程中运行所有 GUI 内容并使用这些postGUI*
函数进行每次访问。但是,当我将最后一行更改mainAxn
为
forkIO mainGUI
return ()
程序到达末尾时立即返回mainAxn
。我试图通过使用来解决这个问题:
forkIO mainGUI
forever $ return ()
但是 gtk GUI 根本没有打开,我不明白为什么。
这样做的正确方法是什么?我错过了什么?