在Gtk2hs中渲染Cairo更新的正确方法是什么?

时间:2015-11-12 07:42:39

标签: haskell cairo gtk2hs

我正在编写一个具有单击并拖动功能的Haskell程序,因此每次鼠标移动事件都会向窗口绘制更新。目前我正在使用

renderWithDrawable myCanvas update

然而这很多都是闪烁的。我的理解是我需要创建一个单独的drawable(一个“表面”?),渲染到它,然后在一次操作中将它blit到屏幕窗口。但是我对这种方法的正确方法感到困惑。

我找到了drawWindowBeginPaintRegion,其中讨论了消除闪烁的问题。 但是根据Haddock文档,它在Gtk3 中被删除了。所以我不确定我是否应该使用它,因为它似乎已被弃用。

我在开罗也找到了renderWithSimilarSurface,这似乎做了类似的事情。

我也不确定这些函数与renderWithDrawable的关系如何:我是否必须在函数中使用它们,或者是什么?

这样做的正确方法是什么?

修改

这在开罗似乎是一件众所周知的事情。我正在试图弄清楚如何在Haskell中处理这个问题。

1 个答案:

答案 0 :(得分:4)

执行此操作的正确方法是确保所有绘图都来自公开事件,并在事件提供的绘制窗口上操作。您可以将区域标记为“脏”,并使用drawWindowInvalidateRectdrawWindowInvalidateRegionwidgetQueueDraw触发合成公开事件。

下面是设置绘图管道的快速工作示例。它摘自一个自定义的Viewport类型,它可以在拖拽和释放操作上进行Google地图样式平移和平滑运动,这是我前段时间为侧面项目构建的。为了支持这一点,它必须重绘鼠标运动事件,因此它解决了与您描述的问题类似的用例。我用...忽略了不相关的东西,以突出重点。我刚刚将完整的项目上传到github,因此您可以浏览回购以查看Viewport的完整详细信息。 (已经过了好几年了,所以可能还有一点点苦差事 - 不要指望这个项目只是用现代的GHC /包来构建和运行。)

viewportNew :: Viewport -> IO DrawingArea
viewportNew v = do
    da <- drawingAreaNew
    -- ...
    on da exposeEvent $ exposeViewport posRef (draw v)
    -- ...

exposeViewport :: IORef Position -> RegionRenderer -> EventM EExpose Bool
exposeViewport posRef draw = do
    dw      <- eventWindow
    region  <- eventRegion >>= liftIO . regionGetRectangles
    -- ...
    liftIO . renderWithDrawable dw $ do
        -- Cairo () action goes here
        -- can reference region to decide which things to draw
        draw region
    return True -- see documentation of exposeEvent for what this means

此模板应该利用gtk的内置双缓冲功能,并使用gtkgtk3包。