2015-11-20 3 views
1

Я написал небольшую программу, которая отображает в окне первые 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 

EDIT:

для 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)) 

но не correct.Can вы мне помочь?

ошибка:

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

Я не знаком с библиотекой вы используете, но я ожидаю, что вы переписываете отдельные значения вместо того, чтобы накапливать список отображаемых значений. 'a <-forM [1..30] (\ t -> labelSetText (display gui) (показать $ fib t))' – Daenyth

+0

Да, ожидаемое поведение должно отображать значения, как только они вычисляются – lolveley

+0

И если вы вычислить их слишком быстро? Предположим, что все вычисления завершены за 0.1 секунд, как это должно отображаться? – Daenyth

ответ

2

GTK является однопоточным. Таким образом, хотя ваш код в guiAnswer вызовет labelSetText, поскольку вещи отображаются, на самом деле они не будут использовать эти данные до тех пор, пока не вернется guiAnswer.

Blind guess: Попробуйте выполнить mainContextIteration mainContextDefault False после labelSetText.

Лучшее угадывание: Запустите вычисление в другом потоке. Но будьте осторожны, что все взаимодействия с gtk должны произойти из основного потока, поэтому вам придется столкнуться с некоторыми проблемами, чтобы синхронизировать это.

Много лет назад я реализовал такой дисплей-а-расчет-происходит функциональность для fractal renderer, но я не уверен, что я по-прежнему выступать в этом стиле :-)

+0

Будут проблемы с синхронизацией, но не так много: gtk предлагает 'postGUIAsync' (и' postGUISync') для более удобной синхронизации. –

+0

Отлично. Это должно сделать прямое решение на основе исходного кода, обернув 'guiAnswer' в' forkIO' и обернув 'labelSetText' внутри' postGUIAsync'. Кто-нибудь ухаживает за тестом и отправляет ответ? –

+0

благодарит joachim за обмен кодом! – lolveley

Смежные вопросы