我正在编写一个具有单击并拖动功能的Haskell程序,因此每次鼠标移动事件都会向窗口绘制更新。目前我正在使用
renderWithDrawable myCanvas update
然而这很多都是闪烁的。我的理解是我需要创建一个单独的drawable(一个“表面”?),渲染到它,然后在一次操作中将它blit到屏幕窗口。但是我对这种方法的正确方法感到困惑。
我找到了drawWindowBeginPaintRegion
,其中讨论了消除闪烁的问题。
但是根据Haddock文档,它在Gtk3 中被删除了。所以我不确定我是否应该使用它,因为它似乎已被弃用。
我在开罗也找到了renderWithSimilarSurface
,这似乎做了类似的事情。
我也不确定这些函数与renderWithDrawable
的关系如何:我是否必须在函数中使用它们,或者是什么?
这样做的正确方法是什么?
修改
这在开罗似乎是一件众所周知的事情。我正在试图弄清楚如何在Haskell中处理这个问题。
答案 0 :(得分:4)
执行此操作的正确方法是确保所有绘图都来自公开事件,并在事件提供的绘制窗口上操作。您可以将区域标记为“脏”,并使用drawWindowInvalidateRect
,drawWindowInvalidateRegion
或widgetQueueDraw
触发合成公开事件。
下面是设置绘图管道的快速工作示例。它摘自一个自定义的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的内置双缓冲功能,并使用gtk
和gtk3
包。