1

举个这样的例子。如何使用 gtk 和 haskell 进行 2d 双缓冲。我想将基元渲染到屏幕外缓冲区并翻转。此代码仅呈现像素/矩形。我想使用双缓冲方法添加运动。

import Graphics.UI.Gtk
import Graphics.UI.Gtk.Gdk.GC
import Graphics.UI.Gtk hiding (Color, Point, Object)

defaultFgColor :: Color
defaultFgColor = Color 65535 65535 65535

defaultBgColor :: Color
defaultBgColor = Color 0 0 0

renderScene d ev = do
    dw     <- widgetGetDrawWindow d
    (w, h) <- widgetGetSize d
    gc     <- gcNew dw
    let fg = Color  (round (65535 * 205))
                    (round (65535 * 0))
                    (round (65535 * 0))
    gcSetValues gc $ newGCValues { foreground = fg }
    drawPoint dw gc (120, 120)
    drawPoint dw gc (22, 22)
    drawRectangle dw gc True 20 20 20 20
    return True

main :: IO ()   
main = do
    initGUI
    window  <- windowNew
    drawing <- drawingAreaNew
    windowSetTitle window "Cells"
    containerAdd window drawing
    let bg = Color  (round (65535 * 205))
                    (round (65535 * 205))
                    (round (65535 * 255))
    widgetModifyBg drawing StateNormal bg
    onExpose drawing (renderScene drawing)

    onDestroy window mainQuit
    windowSetDefaultSize window 800 600
    windowSetPosition window WinPosCenter
    widgetShowAll window
    mainGUI
4

2 回答 2

2

这就是我用来在绘图区域用 cairo 绘画并避免闪烁的方法。尝试将此代码添加到您的 renderScene 函数:

  -- Get the draw window (dw) and its size (w,h)
  -- ...

  regio <- regionRectangle $ Rectangle 0 0 w h
  drawWindowBeginPaintRegion dw regio

  -- Put paiting code here
  -- ..

  drawWindowEndPaint dw

您的最终代码可能如下所示:

import Graphics.UI.Gtk
import Graphics.UI.Gtk.Gdk.GC
import Graphics.UI.Gtk hiding (Color, Point, Object)
import Data.IORef

defaultFgColor :: Color
defaultFgColor = Color 65535 65535 65535

defaultBgColor :: Color
defaultBgColor = Color 0 0 0

renderScene pref d _ev = renderScene' pref d

renderScene' :: IORef Int -> DrawingArea -> IO Bool
renderScene' pref d = do
    dw     <- widgetGetDrawWindow d
    (w, h) <- widgetGetSize d
    regio <- regionRectangle $ Rectangle 0 0 w h

    pos <- readIORef pref
    -- Go around, CCW, in a circle of size 20, centered at (100,100)
    let x = 100 + round ( 20 * sin (fromIntegral pos * pi * 2 / 360) )
        y = 100 + round ( 20 * cos (fromIntegral pos * pi * 2 / 360) )
        pos' = (pos + 1) `mod` 360
    writeIORef pref pos'

    drawWindowBeginPaintRegion dw regio
    gc     <- gcNew dw
    let fg = Color  (round (65535 * 205))
                    (round (65535 * 0))
                    (round (65535 * 0))
    gcSetValues gc $ newGCValues { foreground = fg }
    drawPoint dw gc (120, 120)
    drawPoint dw gc (22, 22)
    drawRectangle dw gc True x y 20 20
    -- Paint an extra rectangle
    drawRectangle dw gc True 200 200 200 200
    drawWindowEndPaint dw
    return True

main :: IO ()   
main = do
    initGUI
    window  <- windowNew
    drawing <- drawingAreaNew
    windowSetTitle window "Cells"
    containerAdd window drawing
    let bg = Color  (round (65535 * 205))
                    (round (65535 * 205))
                    (round (65535 * 255))
    widgetModifyBg drawing StateNormal bg

    pref <- newIORef 0

    onExpose drawing (renderScene pref drawing)
    timeoutAdd (renderScene' pref drawing) 10

    onDestroy window mainQuit
    windowSetDefaultSize window 800 600
    windowSetPosition window WinPosCenter
    widgetShowAll window
    mainGUI
于 2011-03-15T10:25:12.580 回答
0

看看ThreadScope可能是一个想法。滚动是用非常接近双缓冲的东西实现的。这是我认为他们所做的简化版本:

prev_surface <- readIORef prevView
win <- widgetGetDrawWindow timelineDrawingArea
renderWithDrawable win $ do

  -- Create new surface based on the old one
  new_surface <- liftIO $ createSimilarSurface [...]
  renderWith new_surface $ do
    setSourceSurface prev_surface off 0
    Cairo.rectangle [...]
    Cairo.fill
    [... render newly exposed stuff ...]
  surfaceFinish new_surface

  -- Save back new view
  liftIO $ writeIORef prevView new_surface

  -- Paint new view
  setSourceSurface new_surface 0 0
  setOperator OperatorSource
  paint

实际代码可以在Timeline/Render.hs. 不知道这是否是最好的方法,但在实践中似乎效果很好。我希望这有帮助。

于 2011-03-15T15:40:49.447 回答