我写了一个小程序,在窗口中显示Fibonacci序列的前30个项。但是,它不起作用。我的程序(见下文)计算所有术语,但只显示最后一个术语。我想在计算后立即显示所有30个术语。我该怎么办?
module Main where
import Control.Monad (forM)
import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade
fib :: Int -> Integer
fib 1 = 1
fib 2 = 1
fib n = fib(n-1)+fib(n-2)
data GUI = GUI {
mainWin :: Window,
clickMe :: Button,
display :: Label
}
loadGlade :: IO GUI
loadGlade = do
Just xml <- xmlNew "gladeFile.glade"
mw <- xmlGetWidget xml castToWindow "wdwFirst"
bc <- xmlGetWidget xml castToButton "btnClick"
ld <- xmlGetWidget xml castToLabel "lblDisplay"
return $ GUI mw bc ld
connectGui :: GUI -> IO (ConnectId Button)
connectGui gui = do
onDestroy (mainWin gui) mainQuit
onClicked (clickMe gui) (guiAnswer gui)
guiAnswer :: GUI -> IO()
guiAnswer gui = do
a<-forM [1..30] (\t -> labelSetText (display gui) (show $ fib t))
--labelSetText (display gui) "WELCOME!!"
putStr ""
main :: IO ()
main = do
initGUI
gui <- loadGlade
connectGui gui
widgetShowAll (mainWin gui)
mainGUI
编辑:
对于postGuiAsync,我试过这个:
guiAnswer :: GUI -> IO()
guiAnswer gui = do
a<-forM [1..40] (\t -> postGUIAsync $ labelSetText (display gui) (show $ fib t))
--labelSetText (display gui) "WELCOME!!"
--mainContextIteration mainContextDefault False
print ""
但没有成功(它仍然只显示最终的数字),我不确定我的代码。
EDIT2: 我试过这个:
guiAnswer :: GUI -> IO()
guiAnswer gui = do
forkIO $ forM_ [1..40] (\t -> postGUIAsync $ labelSetText (display gui) (show $ fib t))
但这不正确。你能帮助我吗?
错误是:
Couldn't match type `GHC.Conc.Sync.ThreadId' with `()'
Expected type: IO ()
Actual type: IO GHC.Conc.Sync.ThreadId
In a stmt of a 'do' block:
forkIO
$ forM_
[1 .. 40]
(\ t -> postGUIAsync $ labelSetText (display gui) (show $ fib t))
In the expression:
do { forkIO
$ forM_
[1 .. 40]
(\ t -> postGUIAsync $ labelSetText (display gui) (show $ fib t)) }
答案 0 :(得分:2)
GTK是单线程的。因此,虽然guiAnswer
中的代码确实会在显示内容时调用labelSetText
,但在guiAnswer
返回之前,实际上不会使用该数据。
盲目猜测:尝试在mainContextIteration mainContextDefault False
后运行labelSetText
。
更好的猜测:在不同的线程中运行计算。但要注意所有gtk交互必须从主线程发生,所以你将不得不经历一些麻烦来同步它。
很多年前,我为fractal renderer实现了这样一种计算显示功能,但我不确定我是否仍然提倡这种风格: - )