2016-04-15 55 views
1

我預計將吸引Mandelbrot集一個小程序,但我得到這個錯誤:哈斯克爾和GTK:「widgetGetDrawWindow:無DrawWindow」

user error (widgetGetDrawWindow: no DrawWindow available (the widget is probably not realized)) 

程序: - 初始化圖形化的東西, - 計算要顯示的點, - 繪製這些點

沒有語法和編譯錯誤,上面的錯誤在我啓動二進制文件時顯示。

這裏是代碼:

module Main where 

import Graphics.UI.Gtk 
import Graphics.UI.Gtk.Gdk.GC 
import Graphics.UI.Gtk.Windows.Window 
import Graphics.UI.Gtk.Misc.DrawingArea 
import System.Random 
import   Control.Monad   (when,void) 


k :: Int 
k=100 -- 100 : after launching, u must wait less than 10s 

mandelbrot :: Double -> Double -> Bool 
mandelbrot a b = 
    let 
    mandelrec :: Double -> Double -> Int -> Bool 
    mandelrec x y i 
     | (x * x + y * y > 4) = False 
     | (i==k) && (x * x + y * y <= 4) = True 
     | otherwise = mandelrec x' y' (i+1) 
      where x' = x * x - y * y + a 
        y' = 2 * x * y + b 
    in mandelrec 0 0 0 

colonnes :: Double -> [(Int, Double)] 
colonnes w = [ (t,(fromIntegral t)/w*4-2) | t<-[0..((floor w)-1)] ] 

lignes :: Double -> [(Int, Double)] 
lignes h = [ (t,(fromIntegral t)/h*4-2) | t<-[0..((floor h)-1)] ] 

points :: Double -> Double -> [((Int, Double), (Int, Double))] 
points w h = [ (colonne,ligne)| colonne <- colonnes w,ligne <- lignes h] 


main :: IO() 
main = do 
    putStrLn "Hello World" 
    initGUI 
    win <- windowNew 
    onDestroy win mainQuit 
    dAre <- drawingAreaNew 
    dAre `onSizeRequest` return (Requisition 500 300) 
    dAre `onExpose` drawCanvas dAre 
    win `containerAdd` dAre 

    --drawWin <- widgetGetDrawWindow dAre 
    --drawWindowClear drawWin 

    mapM_ (affiche dAre) (points 500 300) 


    widgetShowAll win 
    mainGUI 

affiche2 :: DrawingArea -> Int -> Int -> IO Bool 
affiche2 can a b = do 
    drawWin <- widgetGetDrawWindow can 
    gece <- gcNew drawWin 
    drawLine drawWin gece (a,b) (a,b) 
    widgetQueueDraw can 
    return True 

affiche :: DrawingArea -> ((Int,Double), (Int,Double)) -> IO() 
affiche can ((a0,a), (b0,b)) = 
    when (mandelbrot a b) $ void (affiche2 can a0 b0) 

drawCanvas :: DrawingArea -> event -> IO Bool 
drawCanvas can _evt = do 
    drawWin <- widgetGetDrawWindow can 
    drawWindowClear drawWin 
    gece <- gcNew drawWin 
    x1 <- randomRIO (0,500) 
    x2 <- randomRIO (0,500) 
    y1 <- randomRIO (0,300) 
    y2 <- randomRIO (0,300) 
    drawLine drawWin gece (x1,y1) (x2,y2) 
    widgetQueueDraw can 
    --drawLine drawWin gece (10,10) (100,100) 
    return True 

回答

1

有幾件事情怎麼回事:

  • 我可能是錯的,但我認爲widgetQueueDraw將僅請求畫布的刷新。既然你已經畫出來了,我的猜測是它會被忽略。

  • 即使你想標記畫布需要刷新到屏幕緩衝區,這一切都在同一個線程中運行的,你有一個懸而未決的計算,直到它的自由運行其他操作(如沖洗帆布)。所以,一切都會先畫出來,然後再呈現。

我不認爲有一種強制畫布呈現的乾淨方式。如果是這樣,你需要的是使用多個線程。下面是一個工作示例(請注意,所有Gtk操作都需要在UI線程中運行,這由postGUISync確保)。您需要使用嵌入並使用線程運行時系統(又名RTS)的-threaded標誌進行編譯。

module Main where 

import Control.Concurrent 
import Graphics.UI.Gtk 
import Graphics.UI.Gtk.Gdk.GC 
import Graphics.UI.Gtk.Windows.Window 
import Graphics.UI.Gtk.Misc.DrawingArea 
import System.Random 
import   Control.Monad   (when,void) 


k :: Int 
k=100 -- 100 : after launching, u must wait less than 10s 

mandelbrot :: Double -> Double -> Bool 
mandelbrot a b = 
    let 
    mandelrec :: Double -> Double -> Int -> Bool 
    mandelrec x y i 
     | (x * x + y * y > 4) = False 
     | (i==k) && (x * x + y * y <= 4) = True 
     | otherwise = mandelrec x' y' (i+1) 
      where x' = x * x - y * y + a 
        y' = 2 * x * y + b 
    in mandelrec 0 0 0 

colonnes :: Double -> [(Int, Double)] 
colonnes w = [ (t,(fromIntegral t)/w*4-2) | t<-[0..((floor w)-1)] ] 

lignes :: Double -> [(Int, Double)] 
lignes h = [ (t,(fromIntegral t)/h*4-2) | t<-[0..((floor h)-1)] ] 

points :: Double -> Double -> [((Int, Double), (Int, Double))] 
points w h = [ (colonne,ligne)| colonne <- colonnes w,ligne <- lignes h] 


main :: IO() 
main = do 
    putStrLn "Hello World" 
    initGUI 
    win <- windowNew 
    onDestroy win mainQuit 
    dAre <- drawingAreaNew 
    dAre `onSizeRequest` return (Requisition 500 300) 
    dAre `onExpose` drawCanvas dAre 
    win `containerAdd` dAre 

    widgetShowAll win 
    mainGUI 

affiche2 :: DrawingArea -> Int -> Int -> IO Bool 
affiche2 can a b = do 
    postGUISync $ do drawWin <- widgetGetDrawWindow can 
        gece <- gcNew drawWin 
        drawLine drawWin gece (a,b) (a,b) 
    return True 

affiche :: DrawingArea -> ((Int,Double), (Int,Double)) -> IO() 
affiche can ((a0,a), (b0,b)) = 
    when (mandelbrot a b) $ void (affiche2 can a0 b0) 

drawCanvas :: DrawingArea -> event -> IO Bool 
drawCanvas can _evt = do 
    drawWin <- widgetGetDrawWindow can 
    drawWindowClear drawWin 
    gece <- gcNew drawWin 
    forkIO $ mapM_ (affiche can) (points 500 300) 
    return True 
+0

感謝,我得到了一些不錯的東西,並對點進行了排列組合。但我仍然有很多Haskell要學習:-( – lolveley

2

好,我解決它通過將mapM_語句轉換成updateCanvas功能,但所有的點後,將顯示所有的圖紙計算,這是不是我會喜歡獲得:因爲mandelbrot集合中的部分越小,計算時間就越長,我希望看到繪圖創建時不會等待很長時間。

你知道如何達到這個目標嗎?

這裏是工作代碼:

module Main where 

import Graphics.UI.Gtk 
import Graphics.UI.Gtk.Gdk.GC 
import Graphics.UI.Gtk.Windows.Window 
import Graphics.UI.Gtk.Misc.DrawingArea 
import System.Random 
import   Control.Monad   (when,void) 


k :: Int 
k=10000 -- 100 : after launching, u must wait less than 10s 

mandelbrot :: Double -> Double -> Bool 
mandelbrot a b = 
    let 
    mandelrec :: Double -> Double -> Int -> Bool 
    mandelrec x y i 
     | (x * x + y * y > 4) = False 
     | (i==k) && (x * x + y * y <= 4) = True 
     | otherwise = mandelrec x' y' (i+1) 
      where x' = x * x - y * y + a 
        y' = 2 * x * y + b 
    in mandelrec 0 0 0 

colonnes :: Double -> [(Int, Double)] 
colonnes w = [ (t,(fromIntegral t)/w*4-2) | t<-[0..((floor w)-1)] ] 

lignes :: Double -> [(Int, Double)] 
lignes h = [ (t,(fromIntegral t)/h*4-2) | t<-[0..((floor h)-1)] ] 

points :: Double -> Double -> [((Int, Double), (Int, Double))] 
points w h = [ (colonne,ligne)| colonne <- colonnes w,ligne <- lignes h] 


main :: IO() 
main = do 
    putStrLn "Hello World" 
    initGUI 
    win <- windowNew 
    onDestroy win mainQuit 
    dAre <- drawingAreaNew 
    dAre `onSizeRequest` return (Requisition 500 300) 
    dAre `onExpose` drawCanvas dAre 
    win `containerAdd` dAre 

    --drawWin <- widgetGetDrawWindow dAre 
    --drawWindowClear drawWin 

    --mapM_ (affiche dAre) (points 500 300) 


    widgetShowAll win 
    mainGUI 

affiche2 :: DrawingArea -> Int -> Int -> IO Bool 
affiche2 can a b = do 
    drawWin <- widgetGetDrawWindow can 
    gece <- gcNew drawWin 
    drawLine drawWin gece (a,b) (a,b) 
    --drawLine drawWin gece (10,10) (100,100) 
    widgetQueueDraw can 
    return True 

affiche :: DrawingArea -> ((Int,Double), (Int,Double)) -> IO() 
affiche can ((a0,a), (b0,b)) = 
    when (mandelbrot a b) $ void (affiche2 can a0 b0) 

drawCanvas :: DrawingArea -> event -> IO Bool 
drawCanvas can _evt = do 
    drawWin <- widgetGetDrawWindow can 
    drawWindowClear drawWin 
    gece <- gcNew drawWin 
    --x1 <- randomRIO (0,500) 
    --x2 <- randomRIO (0,500) 
    --y1 <- randomRIO (0,300) 
    --y2 <- randomRIO (0,300) 
    --drawLine drawWin gece (x1,y1) (x2,y2) 
    mapM_ (affiche can) (points 500 300) 
    widgetQueueDraw can 
    --drawLine drawWin gece (10,10) (100,100) 
    return True 
+1

如果你有另一個問題,你應該問另一個問題,而不是在你的答案中包括它。 – user2407038