haskell & gtk : "widgetGetDrawWindow: no DrawWindow available"
haskell & gtk : "widgetGetDrawWindow: no DrawWindow available"
我有一个小程序可以用来绘制 mandelbrot 集,但是我得到了这个错误:
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
好吧,我通过将 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
发生了一些事情:
我可能错了,但我认为 widgetQueueDraw
只会请求刷新 canvas。既然你已经在画了,我猜它会被忽略。
即使您尝试将 canvas 标记为 需要刷新到屏幕缓冲区 ,也只是 运行ning在同一线程中,您有一个待处理的计算,直到它可以自由地进行 运行 其他操作(例如刷新 canvas)。所以,一切都是先画后呈现。
我认为没有一种干净的方法可以强制显示 canvas。如果是这样,你需要的是使用多线程。下面是一个工作示例(请注意,所有 Gtk 操作都需要在 UI 线程中进行 运行,这是由 postGUISync
确保的)。您需要使用 -threaded
标志对其进行编译,该标志嵌入并使用线程 运行 时间系统(又名 RTS)。
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
我有一个小程序可以用来绘制 mandelbrot 集,但是我得到了这个错误:
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
好吧,我通过将 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
发生了一些事情:
我可能错了,但我认为
widgetQueueDraw
只会请求刷新 canvas。既然你已经在画了,我猜它会被忽略。即使您尝试将 canvas 标记为 需要刷新到屏幕缓冲区 ,也只是 运行ning在同一线程中,您有一个待处理的计算,直到它可以自由地进行 运行 其他操作(例如刷新 canvas)。所以,一切都是先画后呈现。
我认为没有一种干净的方法可以强制显示 canvas。如果是这样,你需要的是使用多线程。下面是一个工作示例(请注意,所有 Gtk 操作都需要在 UI 线程中进行 运行,这是由 postGUISync
确保的)。您需要使用 -threaded
标志对其进行编译,该标志嵌入并使用线程 运行 时间系统(又名 RTS)。
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