User interface 在计算序列项时显示序列项

User interface 在计算序列项时显示序列项,user-interface,haskell,User Interface,Haskell,我写了一个小程序,在窗口中显示斐波那契序列的前30项。但是,它不起作用。我的程序(见下文)计算所有术语,但只显示最后一个术语。我想显示所有30项,一旦计算出来。我该怎么办 module Main where import Control.Monad (forM) import Graphics.UI.Gtk import Graphics.UI.Gtk.Glade fib :: Int -> Integer f

我写了一个小程序,在窗口中显示斐波那契序列的前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
但这是不对的。你能帮我吗

错误是:

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)) }

GTK是单螺纹的。因此,虽然
guiAnswer
中的代码确实会在显示内容时调用
labelSetText
,但在
guiAnswer
返回之前,不会实际使用该数据

盲猜:尝试在
labelSetText
之后运行
mainContextIteration mainContextDefault False

更好的猜测:在不同的线程中运行计算。但是请注意,所有gtk交互都必须从主线程进行,因此您必须经历一些麻烦才能同步


许多年前,我为a实现了“计算发生时显示”功能,但我不确定我是否仍会提倡这种风格:-)

我不熟悉您使用的库,但我希望您正在覆盖单个值,而不是累积要显示的值列表<代码>labelSetText(显示gui)(show$fib t))是的,预期的行为是在计算值时立即显示值,如果计算太快?假设所有的计算都在0.1秒内完成,它应该如何显示?这就是我使用斐波那契套件的原因;compute 30术语需要几秒钟,只有在这几秒钟之后,标签的文本才会更改。这就是我发布这条消息的原因:我认为整个套件都是在显示之前计算出来的。但你是对的:这还是有点快。如果你能将代码和所有相关文件(即
xml
文件)一起上传到某个地方,会更容易得到帮助。然后我可以很容易地测试我的建议:-)会有一些同步问题,但不会太多:gtk提供了
postGUIAsync
(和
postGUISync
)以实现更方便的同步。太好了。这应该是基于原始代码的直接解决方案,方法是将
guiAnswer
包装在
forkIO
中,并将
labelSetText
包装在
postGUIAsync
中。有人关心测试和发布答案吗?@loveley,别忘了把
guiAnswer
(或者只是
表单
行)包装在
forkIO
中。对不起,我不知道怎么做。你能给我看看吗?我得到了一些关于mapM函数的错误(它需要forkIO[()]而不是forkIO())使用
mapM\uuu
而不是
mapM
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)) }