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

What is the right way to render Cairo updates in Gtk2hs?

我正在编写一个具有点击和拖动功能的 Haskell 程序,因此每次鼠标移动事件都会将更新绘制到 window。目前我正在使用

renderWithDrawable myCanvas update

然而,这闪烁了很多。我的理解是我需要创建一个单独的可绘制对象(一个 "surface"?),对其进行渲染,然后在一次操作中将其 blit 到屏幕上 window。但是我对正确的方法感到困惑。

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

我在开罗也发现了 renderWithSimilarSurface,它似乎在做类似的事情。

我也不确定这些函数与 renderWithDrawable 有什么关系:我必须在该函数内部使用它们吗?

正确的做法是什么?

编辑

这在开罗好像是家喻户晓的事情。我想弄清楚如何在 Haskell.

中处理这个问题

执行此操作的正确方法是确保您的所有绘图都来自公开事件,并对事件提供的绘图 window 进行操作。您可以将区域标记为 "dirty" 并使用 drawWindowInvalidateRectdrawWindowInvalidateRegionwidgetQueueDraw.

触发合成公开事件

下面是一个设置绘图管道的快速示例。它摘自一个自定义的 Viewport 类型,它在拖放操作上进行 Google-maps 风格的平移,动作流畅,这是我前段时间为一个副项目构建的。为了支持这一点,它必须重新绘制鼠标运动事件,因此它解决了与您描述的问题类似的用例。我用 ... 删除了不相关的内容以突出显示重要的部分。我刚才已经将完整的项目上传到 github,因此您可以浏览 repo 以查看 Viewport 的完整详细信息。 (不过已经好几年了,所以可能有一点比特腐烂——不要指望这个项目只是用现代 GHCs/packages 构建和 运行。)

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 包一起使用。